Mercurial > pidgin.yaz
annotate src/gtkimhtml.c @ 9456:0577bb34622d
[gaim-migrate @ 10280]
This fixes bug #964043
We were truncating the port to 4 ascii digits, because our buffer was too
small. Oops. Let this be an example to you, not all users are on crack.
This bug was somewhat confusing by the fact that the spin button to choose
the port is only big enough to show 4 digits at a time. That's completely
unrelated though, you can hit HOME and END and stuff to see all the digits
and it saves file and all.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Tue, 06 Jul 2004 06:22:14 +0000 |
parents | d0380151c6d1 |
children | 8a4797a608ae |
rev | line source |
---|---|
1428 | 1 /* |
2 * GtkIMHtml | |
3 * | |
8046 | 4 * Gaim is the legal property of its developers, whose names are too numerous |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
1428 | 7 * |
8 * This program is free software; you can redistribute it and/or modify | |
9 * under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 | |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
24 #ifdef HAVE_CONFIG_H |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
25 #include <config.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
26 #endif |
8526 | 27 #include "debug.h" |
8091 | 28 #include "util.h" |
1428 | 29 #include "gtkimhtml.h" |
7358 | 30 #include "gtksourceiter.h" |
1428 | 31 #include <gtk/gtk.h> |
4895 | 32 #include <glib/gerror.h> |
4046 | 33 #include <gdk/gdkkeysyms.h> |
1428 | 34 #include <string.h> |
35 #include <ctype.h> | |
36 #include <stdio.h> | |
4629 | 37 #include <stdlib.h> |
1428 | 38 #include <math.h> |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
39 #ifdef HAVE_LANGINFO_CODESET |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
40 #include <langinfo.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
41 #include <locale.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
42 #endif |
8692 | 43 #ifdef _WIN32 |
44 #include <windows.h> | |
45 #endif | |
1428 | 46 |
4417 | 47 #ifdef ENABLE_NLS |
48 # include <libintl.h> | |
49 # define _(x) gettext(x) | |
50 # ifdef gettext_noop | |
51 # define N_(String) gettext_noop (String) | |
52 # else | |
53 # define N_(String) (String) | |
54 # endif | |
55 #else | |
56 # define N_(String) (String) | |
57 # define _(x) (x) | |
58 #endif | |
59 | |
4735 | 60 #include <pango/pango-font.h> |
61 | |
5105 | 62 /* GTK+ < 2.2.2 hack, see ui.h for details. */ |
63 #ifndef GTK_WRAP_WORD_CHAR | |
64 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD | |
65 #endif | |
66 | |
4735 | 67 #define TOOLTIP_TIMEOUT 500 |
68 | |
8786 | 69 /* GTK+ 2.0 hack */ |
70 #if (!GTK_CHECK_VERSION(2,2,0)) | |
71 #define gtk_widget_get_clipboard(x, y) gtk_clipboard_get(y) | |
72 #endif | |
73 | |
9300 | 74 static gboolean |
75 gtk_text_view_drag_motion (GtkWidget *widget, | |
76 GdkDragContext *context, | |
77 gint x, | |
78 gint y, | |
79 guint time); | |
80 | |
8677 | 81 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); |
8061 | 82 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); |
8505 | 83 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); |
8698 | 84 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter); |
9300 | 85 static void gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data); |
8091 | 86 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); |
8677 | 87 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml); |
8931 | 88 static void hijack_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data); |
89 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data); | |
90 static void paste_plaintext_received_cb (GtkClipboard *clipboard, const gchar *text, gpointer data); | |
8061 | 91 |
3922 | 92 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
93 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ | |
94 #define MAX_FONT_SIZE 7 | |
5367 | 95 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
8380 | 96 static gdouble _point_sizes [] = { .69444444, .8333333, 1, 1.2, 1.44, 1.728, 2.0736}; |
2349
60c716c32c40
[gaim-migrate @ 2362]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2348
diff
changeset
|
97 |
8498 | 98 enum { |
8677 | 99 TARGET_HTML, |
8061 | 100 TARGET_UTF8_STRING, |
101 TARGET_COMPOUND_TEXT, | |
102 TARGET_STRING, | |
103 TARGET_TEXT | |
104 }; | |
105 | |
8091 | 106 enum { |
9300 | 107 DRAG_URL, |
108 DRAG_HTML, | |
109 DRAG_UTF8_STRING, | |
110 DRAG_COMPOUND_TEXT, | |
111 DRAG_STRING, | |
112 DRAG_TEXT, | |
8091 | 113 }; |
114 | |
8420 | 115 enum { |
116 URL_CLICKED, | |
117 BUTTONS_UPDATE, | |
118 TOGGLE_FORMAT, | |
8427 | 119 CLEAR_FORMAT, |
8506 | 120 UPDATE_FORMAT, |
8420 | 121 LAST_SIGNAL |
122 }; | |
123 static guint signals [LAST_SIGNAL] = { 0 }; | |
124 | |
8061 | 125 GtkTargetEntry selection_targets[] = { |
8566 | 126 { "text/html", 0, TARGET_HTML }, |
8061 | 127 { "UTF8_STRING", 0, TARGET_UTF8_STRING }, |
128 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, | |
129 { "STRING", 0, TARGET_STRING }, | |
130 { "TEXT", 0, TARGET_TEXT}}; | |
131 | |
8091 | 132 GtkTargetEntry link_drag_drop_targets[] = { |
9300 | 133 {"text/html", 0, DRAG_HTML }, |
8091 | 134 {"x-url/ftp", 0, DRAG_URL}, |
135 {"x-url/http", 0, DRAG_URL}, | |
136 {"text/uri-list", 0, DRAG_URL}, | |
9300 | 137 {"_NETSCAPE_URL", 0, DRAG_URL}, |
138 { "UTF8_STRING", 0, DRAG_UTF8_STRING }, | |
139 { "COMPOUND_TEXT", 0, DRAG_COMPOUND_TEXT }, | |
140 { "STRING", 0, DRAG_STRING }, | |
141 { "TEXT", 0, DRAG_TEXT}}; | |
142 | |
8091 | 143 |
8692 | 144 #ifdef _WIN32 |
145 /* Win32 clipboard format value, and functions to convert back and | |
146 * forth between HTML and the clipboard format. | |
147 */ | |
148 static UINT win_html_fmt; | |
149 | |
150 static gchar * | |
151 clipboard_win32_to_html(char *clipboard) { | |
8693 | 152 const char *begin, *end; |
8692 | 153 gchar *html; |
154 | |
8693 | 155 begin = strstr(clipboard, "<!--StartFragment"); |
156 while(*begin++ != '>'); | |
8692 | 157 end = strstr(clipboard, "<!--EndFragment"); |
158 html = g_strstrip(g_strndup(begin, (end ? (end - begin) : strlen(begin)))); | |
8707 | 159 return html; |
8692 | 160 } |
161 | |
162 static gchar * | |
163 clipboard_html_to_win32(char *html) { | |
8693 | 164 int length; |
8692 | 165 gchar *ret; |
166 GString *clipboard; | |
167 | |
8693 | 168 if (html == NULL) |
169 return NULL; | |
8692 | 170 |
171 length = strlen(html); | |
172 clipboard = g_string_new ("Version:0.9\r\n"); | |
173 g_string_append(clipboard, "StartHTML:0000000105\r\n"); | |
174 g_string_append(clipboard, g_strdup_printf("EndHTML:%010d\r\n", 143 + length)); | |
175 g_string_append(clipboard, "StartFragment:0000000105\r\n"); | |
176 g_string_append(clipboard, g_strdup_printf("EndFragment:%010d\r\n", 143 + length)); | |
177 g_string_append(clipboard, "<!--StartFragment-->"); | |
178 g_string_append(clipboard, html); | |
179 g_string_append(clipboard, "<!--EndFragment-->"); | |
180 ret = clipboard->str; | |
181 g_string_free(clipboard, FALSE); | |
182 return ret; | |
183 } | |
184 #endif | |
185 | |
4032 | 186 static GtkSmileyTree* |
187 gtk_smiley_tree_new () | |
188 { | |
189 return g_new0 (GtkSmileyTree, 1); | |
190 } | |
191 | |
192 static void | |
193 gtk_smiley_tree_insert (GtkSmileyTree *tree, | |
4263 | 194 GtkIMHtmlSmiley *smiley) |
4032 | 195 { |
196 GtkSmileyTree *t = tree; | |
4263 | 197 const gchar *x = smiley->smile; |
4032 | 198 |
199 if (!strlen (x)) | |
200 return; | |
201 | |
202 while (*x) { | |
203 gchar *pos; | |
204 gint index; | |
205 | |
206 if (!t->values) | |
207 t->values = g_string_new (""); | |
208 | |
209 pos = strchr (t->values->str, *x); | |
210 if (!pos) { | |
211 t->values = g_string_append_c (t->values, *x); | |
212 index = t->values->len - 1; | |
213 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); | |
214 t->children [index] = g_new0 (GtkSmileyTree, 1); | |
215 } else | |
7386 | 216 index = GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str); |
8061 | 217 |
4032 | 218 t = t->children [index]; |
8061 | 219 |
4032 | 220 x++; |
221 } | |
8061 | 222 |
4263 | 223 t->image = smiley; |
4032 | 224 } |
4041 | 225 |
4263 | 226 |
4264 | 227 void gtk_smiley_tree_destroy (GtkSmileyTree *tree) |
4032 | 228 { |
229 GSList *list = g_slist_append (NULL, tree); | |
230 | |
231 while (list) { | |
232 GtkSmileyTree *t = list->data; | |
233 gint i; | |
234 list = g_slist_remove(list, t); | |
7384 | 235 if (t && t->values) { |
4032 | 236 for (i = 0; i < t->values->len; i++) |
237 list = g_slist_append (list, t->children [i]); | |
238 g_string_free (t->values, TRUE); | |
239 g_free (t->children); | |
240 } | |
241 g_free (t); | |
242 } | |
243 } | |
244 | |
5967 | 245 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data) |
246 { | |
247 GdkRectangle rect; | |
8726 | 248 int xminus; |
5967 | 249 |
250 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect); | |
251 if(widget->old_rect.width != rect.width || widget->old_rect.height != rect.height){ | |
252 GList *iter = GTK_IMHTML(widget)->scalables; | |
253 | |
8726 | 254 xminus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(widget)) + |
255 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(widget)); | |
256 | |
5967 | 257 while(iter){ |
258 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data); | |
8726 | 259 scale->scale(scale, rect.width - xminus, rect.height); |
5967 | 260 |
261 iter = iter->next; | |
262 } | |
263 } | |
264 | |
265 widget->old_rect = rect; | |
266 return FALSE; | |
267 } | |
268 | |
269 static gint | |
270 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
271 { | |
272 PangoLayout *layout; | |
273 | |
274 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
275 | |
276 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
277 | |
8061 | 278 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, |
5967 | 279 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, |
280 "tooltip", 0, 0, -1, -1); | |
281 | |
282 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
283 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
284 | |
285 g_object_unref(layout); | |
286 return FALSE; | |
287 } | |
288 | |
289 static gint | |
290 gtk_imhtml_tip (gpointer data) | |
291 { | |
292 GtkIMHtml *imhtml = data; | |
8526 | 293 PangoFontMetrics *font_metrics; |
5967 | 294 PangoLayout *layout; |
8526 | 295 PangoFont *font; |
5967 | 296 |
297 gint gap, x, y, h, w, scr_w, baseline_skip; | |
298 | |
299 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
300 | |
301 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
302 imhtml->tip_timer = 0; | |
303 return FALSE; | |
304 } | |
8061 | 305 |
5967 | 306 if (imhtml->tip_window){ |
307 gtk_widget_destroy (imhtml->tip_window); | |
308 imhtml->tip_window = NULL; | |
309 } | |
310 | |
311 imhtml->tip_timer = 0; | |
312 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
313 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
314 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
315 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
316 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
317 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
318 | |
319 gtk_widget_ensure_style (imhtml->tip_window); | |
320 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
8526 | 321 font = pango_context_load_font(pango_layout_get_context(layout), |
322 imhtml->tip_window->style->font_desc); | |
323 | |
324 if (font == NULL) { | |
325 char *tmp = pango_font_description_to_string( | |
326 imhtml->tip_window->style->font_desc); | |
327 | |
328 gaim_debug(GAIM_DEBUG_ERROR, "gtk_imhtml_tip", | |
329 "pango_context_load_font() couldn't load font: '%s'\n", | |
330 tmp); | |
331 g_free(tmp); | |
332 | |
333 return FALSE; | |
334 | |
335 } | |
336 | |
337 font_metrics = pango_font_get_metrics(font, NULL); | |
8309 | 338 |
5967 | 339 |
340 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
8526 | 341 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font_metrics) + |
342 pango_font_metrics_get_descent(font_metrics))/ 4); | |
5967 | 343 |
344 if (gap < 2) | |
345 gap = 2; | |
8526 | 346 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font_metrics) + |
347 pango_font_metrics_get_descent(font_metrics)); | |
5967 | 348 w = 8 + scr_w; |
349 h = 8 + baseline_skip; | |
350 | |
351 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
352 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
353 y += GTK_WIDGET(imhtml)->allocation.y; | |
354 | |
355 scr_w = gdk_screen_width(); | |
356 | |
357 x -= ((w >> 1) + 4); | |
358 | |
359 if ((x + w) > scr_w) | |
360 x -= (x + w) - scr_w; | |
361 else if (x < 0) | |
362 x = 0; | |
363 | |
8526 | 364 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font_metrics) + |
365 pango_font_metrics_get_descent(font_metrics)); | |
5967 | 366 |
367 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
368 gtk_widget_show (imhtml->tip_window); | |
369 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
370 | |
8526 | 371 pango_font_metrics_unref(font_metrics); |
5967 | 372 g_object_unref(layout); |
373 | |
374 return FALSE; | |
375 } | |
376 | |
377 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
8061 | 378 { |
5967 | 379 GtkTextIter iter; |
380 GdkWindow *win = event->window; | |
381 int x, y; | |
382 char *tip = NULL; | |
383 GSList *tags = NULL, *templist = NULL; | |
384 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
385 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
386 event->x, event->y, &x, &y); | |
387 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
388 tags = gtk_text_iter_get_tags(&iter); | |
389 | |
390 templist = tags; | |
391 while (templist) { | |
392 GtkTextTag *tag = templist->data; | |
393 tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
394 if (tip) | |
395 break; | |
396 templist = templist->next; | |
397 } | |
8061 | 398 |
5967 | 399 if (GTK_IMHTML(imhtml)->tip) { |
400 if ((tip == GTK_IMHTML(imhtml)->tip)) { | |
401 return FALSE; | |
402 } | |
403 /* We've left the cell. Remove the timeout and create a new one below */ | |
404 if (GTK_IMHTML(imhtml)->tip_window) { | |
405 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
406 GTK_IMHTML(imhtml)->tip_window = NULL; | |
407 } | |
8061 | 408 if (GTK_IMHTML(imhtml)->editable) |
409 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->text_cursor); | |
410 else | |
411 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 412 if (GTK_IMHTML(imhtml)->tip_timer) |
413 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
414 GTK_IMHTML(imhtml)->tip_timer = 0; | |
415 } | |
8061 | 416 |
5967 | 417 if(tip){ |
8061 | 418 if (!GTK_IMHTML(imhtml)->editable) |
419 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); | |
420 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, | |
5967 | 421 gtk_imhtml_tip, imhtml); |
422 } | |
8061 | 423 |
5967 | 424 GTK_IMHTML(imhtml)->tip = tip; |
425 g_slist_free(tags); | |
426 return FALSE; | |
427 } | |
428 | |
429 gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer data) | |
430 { | |
431 /* when leaving the widget, clear any current & pending tooltips and restore the cursor */ | |
432 if (GTK_IMHTML(imhtml)->tip_window) { | |
433 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
434 GTK_IMHTML(imhtml)->tip_window = NULL; | |
435 } | |
436 if (GTK_IMHTML(imhtml)->tip_timer) { | |
437 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
438 GTK_IMHTML(imhtml)->tip_timer = 0; | |
439 } | |
8061 | 440 if (GTK_IMHTML(imhtml)->editable) |
441 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->text_cursor); | |
442 else | |
443 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 444 |
8568 | 445 /* propagate the event normally */ |
5967 | 446 return FALSE; |
447 } | |
448 | |
6066 | 449 /* |
450 * XXX - This should be removed eventually. | |
451 * | |
8061 | 452 * This function exists to work around a gross bug in GtkTextView. |
453 * Basically, we short circuit ctrl+a and ctrl+end because they make | |
6066 | 454 * el program go boom. |
455 * | |
8061 | 456 * It's supposed to be fixed in gtk2.2. You can view the bug report at |
6066 | 457 * http://bugzilla.gnome.org/show_bug.cgi?id=107939 |
458 */ | |
8317 | 459 |
460 /* | |
461 * I'm adding some keyboard shortcuts too. | |
462 */ | |
463 | |
464 gboolean gtk_key_pressed_cb(GtkIMHtml *imhtml, GdkEventKey *event, gpointer data) | |
8677 | 465 { |
8317 | 466 char buf[7]; |
467 buf[0] = '\0'; | |
468 | |
6066 | 469 if (event->state & GDK_CONTROL_MASK) |
470 switch (event->keyval) { | |
8539 | 471 #if (!GTK_CHECK_VERSION(2,2,0)) |
8317 | 472 case 'a': |
473 return TRUE; | |
474 break; | |
8677 | 475 |
8317 | 476 case GDK_Home: |
477 return TRUE; | |
478 break; | |
479 | |
480 case GDK_End: | |
481 return TRUE; | |
482 break; | |
8758 | 483 #endif /* !(Gtk+ >= 2.2.0) */ |
8317 | 484 |
485 case 'b': /* ctrl-b is GDK_Left, which moves backwards. */ | |
486 case 'B': | |
8420 | 487 if (imhtml->format_functions & GTK_IMHTML_BOLD) { |
8456 | 488 if(imhtml->html_shortcuts) { |
489 gtk_imhtml_toggle_bold(imhtml); | |
8466 | 490 return TRUE; |
8456 | 491 } |
8420 | 492 } |
8466 | 493 return FALSE; |
8317 | 494 break; |
8654 | 495 |
8317 | 496 case 'i': |
497 case 'I': | |
8481 | 498 if (imhtml->format_functions & GTK_IMHTML_ITALIC) { |
8466 | 499 if(imhtml->html_shortcuts) { |
8456 | 500 gtk_imhtml_toggle_italic(imhtml); |
8466 | 501 return TRUE; |
502 } | |
8481 | 503 } |
8466 | 504 return FALSE; |
8317 | 505 break; |
506 | |
507 case 'u': /* ctrl-u is GDK_Clear, which clears the line. */ | |
508 case 'U': | |
8481 | 509 if (imhtml->format_functions & GTK_IMHTML_UNDERLINE) { |
8466 | 510 if(imhtml->html_shortcuts) { |
8456 | 511 gtk_imhtml_toggle_underline(imhtml); |
8466 | 512 return TRUE; |
513 } | |
8481 | 514 } |
8466 | 515 return FALSE; |
8317 | 516 break; |
517 | |
518 case '-': | |
8420 | 519 if (imhtml->format_functions & GTK_IMHTML_SHRINK) |
520 gtk_imhtml_font_shrink(imhtml); | |
8317 | 521 return TRUE; |
522 break; | |
523 | |
524 case '=': | |
525 case '+': | |
8420 | 526 if (imhtml->format_functions & GTK_IMHTML_GROW) |
527 gtk_imhtml_font_grow(imhtml); | |
8317 | 528 return TRUE; |
529 break; | |
8677 | 530 |
8317 | 531 case '1': strcpy(buf, ":-)"); break; |
532 case '2': strcpy(buf, ":-("); break; | |
533 case '3': strcpy(buf, ";-)"); break; | |
534 case '4': strcpy(buf, ":-P"); break; | |
535 case '5': strcpy(buf, "=-O"); break; | |
536 case '6': strcpy(buf, ":-*"); break; | |
537 case '7': strcpy(buf, ">:o"); break; | |
538 case '8': strcpy(buf, "8-)"); break; | |
539 case '!': strcpy(buf, ":-$"); break; | |
540 case '@': strcpy(buf, ":-!"); break; | |
541 case '#': strcpy(buf, ":-["); break; | |
542 case '$': strcpy(buf, "O:-)"); break; | |
543 case '%': strcpy(buf, ":-/"); break; | |
544 case '^': strcpy(buf, ":'("); break; | |
545 case '&': strcpy(buf, ":-X"); break; | |
546 case '*': strcpy(buf, ":-D"); break; | |
6066 | 547 } |
8456 | 548 if (*buf && imhtml->smiley_shortcuts) { |
549 gtk_imhtml_insert_smiley(imhtml, imhtml->protocol_name, buf); | |
8317 | 550 return TRUE; |
8677 | 551 } |
6066 | 552 return FALSE; |
553 } | |
554 | |
8931 | 555 static void paste_unformatted_cb(GtkMenuItem *menu, GtkIMHtml *imhtml) |
556 { | |
557 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD); | |
558 | |
559 gtk_clipboard_request_text(clipboard, paste_plaintext_received_cb, imhtml); | |
560 | |
561 } | |
562 | |
563 static void hijack_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data) | |
564 { | |
565 GtkWidget *menuitem; | |
566 | |
567 menuitem = gtk_menu_item_new_with_mnemonic(_("Pa_ste As Text")); | |
568 gtk_widget_show(menuitem); | |
569 gtk_widget_set_sensitive(menuitem, | |
570 (imhtml->editable && | |
571 gtk_clipboard_wait_is_text_available( | |
572 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD)))); | |
573 /* put it after "Paste" */ | |
574 gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 3); | |
575 | |
576 g_signal_connect(G_OBJECT(menuitem), "activate", | |
577 G_CALLBACK(paste_unformatted_cb), imhtml); | |
578 } | |
579 | |
8061 | 580 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { |
8681 | 581 char *text; |
8782
5a2b5e4abf3a
[gaim-migrate @ 9544]
Christian Hammond <chipx86@chipx86.com>
parents:
8758
diff
changeset
|
582 gboolean primary; |
8061 | 583 GtkTextIter start, end; |
584 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
585 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
8681 | 586 |
8061 | 587 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); |
588 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
8782
5a2b5e4abf3a
[gaim-migrate @ 9544]
Christian Hammond <chipx86@chipx86.com>
parents:
8758
diff
changeset
|
589 primary = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY) == clipboard; |
8061 | 590 |
591 if (info == TARGET_HTML) { | |
8907 | 592 gsize len; |
8148 | 593 char *selection; |
8061 | 594 GString *str = g_string_new(NULL); |
8681 | 595 if (primary) { |
596 text = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
597 } else | |
598 text = imhtml->clipboard_html_string; | |
8061 | 599 |
600 /* Mozilla asks that we start our text/html with the Unicode byte order mark */ | |
601 str = g_string_append_unichar(str, 0xfeff); | |
602 str = g_string_append(str, text); | |
603 str = g_string_append_unichar(str, 0x0000); | |
8148 | 604 selection = g_convert(str->str, str->len, "UCS-2", "UTF-8", NULL, &len, NULL); |
8719 | 605 gtk_selection_data_set(selection_data, gdk_atom_intern("text/html", FALSE), 16, selection, len); |
8061 | 606 g_string_free(str, TRUE); |
607 g_free(selection); | |
608 } else { | |
8681 | 609 if (primary) { |
610 text = gtk_imhtml_get_text(imhtml, &start, &end); | |
611 } else | |
612 text = imhtml->clipboard_text_string; | |
8061 | 613 gtk_selection_data_set_text(selection_data, text, strlen(text)); |
614 } | |
8681 | 615 if (primary) /* This was allocated here */ |
616 g_free(text); | |
617 } | |
8061 | 618 |
619 static void gtk_imhtml_primary_clipboard_clear(GtkClipboard *clipboard, GtkIMHtml *imhtml) | |
7749 | 620 { |
8061 | 621 GtkTextIter insert; |
622 GtkTextIter selection_bound; | |
623 | |
624 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &insert, | |
625 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert")); | |
626 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &selection_bound, | |
627 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound")); | |
628 | |
629 if (!gtk_text_iter_equal (&insert, &selection_bound)) | |
630 gtk_text_buffer_move_mark (imhtml->text_buffer, | |
631 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"), | |
632 &insert); | |
7749 | 633 } |
7742 | 634 |
8677 | 635 static void copy_clipboard_cb(GtkIMHtml *imhtml, gpointer unused) |
7749 | 636 { |
8681 | 637 GtkTextIter start, end; |
638 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
639 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
640 | |
641 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); | |
642 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
643 | |
8061 | 644 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), |
645 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
646 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
647 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); | |
7346 | 648 |
8681 | 649 if (imhtml->clipboard_html_string) { |
650 g_free(imhtml->clipboard_html_string); | |
651 g_free(imhtml->clipboard_text_string); | |
652 } | |
653 | |
654 imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
655 imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end); | |
656 | |
8692 | 657 #ifdef _WIN32 |
658 /* We're going to still copy plain text, but let's toss the "HTML Format" | |
659 we need into the windows clipboard now as well. */ | |
660 HGLOBAL hdata; | |
661 gchar *clipboard = clipboard_html_to_win32(imhtml->clipboard_html_string); | |
662 gchar *buffer; | |
663 gint length = strlen(clipboard); | |
664 if(clipboard != NULL) { | |
8693 | 665 OpenClipboard(NULL); |
8692 | 666 hdata = GlobalAlloc(GMEM_MOVEABLE, length); |
667 buffer = GlobalLock(hdata); | |
668 memcpy(buffer, clipboard, length); | |
669 GlobalUnlock(hdata); | |
670 SetClipboardData(win_html_fmt, hdata); | |
671 CloseClipboard(); | |
8693 | 672 g_free(clipboard); |
8692 | 673 } |
674 #endif | |
675 | |
8061 | 676 g_signal_stop_emission_by_name(imhtml, "copy-clipboard"); |
677 } | |
678 | |
8698 | 679 static void cut_clipboard_cb(GtkIMHtml *imhtml, gpointer unused) |
680 { | |
681 GtkTextIter start, end; | |
682 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
683 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
684 | |
685 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); | |
686 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
687 | |
688 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), | |
689 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
690 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
691 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); | |
692 | |
693 if (imhtml->clipboard_html_string) { | |
694 g_free(imhtml->clipboard_html_string); | |
695 g_free(imhtml->clipboard_text_string); | |
696 } | |
697 | |
698 imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
699 imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end); | |
700 | |
701 #ifdef _WIN32 | |
702 /* We're going to still copy plain text, but let's toss the "HTML Format" | |
703 we need into the windows clipboard now as well. */ | |
704 HGLOBAL hdata; | |
705 gchar *clipboard = clipboard_html_to_win32(imhtml->clipboard_html_string); | |
706 gchar *buffer; | |
707 gint length = strlen(clipboard); | |
708 if(clipboard != NULL) { | |
709 OpenClipboard(NULL); | |
710 hdata = GlobalAlloc(GMEM_MOVEABLE, length); | |
711 buffer = GlobalLock(hdata); | |
712 memcpy(buffer, clipboard, length); | |
713 GlobalUnlock(hdata); | |
714 SetClipboardData(win_html_fmt, hdata); | |
715 CloseClipboard(); | |
716 g_free(clipboard); | |
717 } | |
718 #endif | |
719 | |
720 if (imhtml->editable) | |
721 gtk_text_buffer_delete_selection(imhtml->text_buffer, FALSE, FALSE); | |
722 g_signal_stop_emission_by_name(imhtml, "cut-clipboard"); | |
723 } | |
724 | |
8931 | 725 static void imhtml_paste_insert(GtkIMHtml *imhtml, const char *text, gboolean plaintext) |
726 { | |
727 GtkTextIter iter; | |
728 GtkIMHtmlOptions flags = plaintext ? 0 : GTK_IMHTML_NO_NEWLINE; | |
729 | |
9028 | 730 if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) |
731 gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE); | |
732 | |
8931 | 733 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer)); |
734 if (!imhtml->wbfo && !plaintext) | |
735 gtk_imhtml_close_tags(imhtml, &iter); | |
736 | |
737 gtk_imhtml_insert_html_at_iter(imhtml, text, flags, &iter); | |
738 gtk_text_buffer_move_mark_by_name(imhtml->text_buffer, "insert", &iter); | |
739 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), gtk_text_buffer_get_insert(imhtml->text_buffer), | |
740 0, FALSE, 0.0, 0.0); | |
741 } | |
742 | |
743 static void paste_plaintext_received_cb (GtkClipboard *clipboard, const gchar *text, gpointer data) | |
744 { | |
745 char *tmp; | |
746 | |
747 if (text == NULL) | |
748 return; | |
749 | |
750 tmp = gaim_escape_html(text); | |
751 imhtml_paste_insert(data, tmp, TRUE); | |
752 g_free(tmp); | |
753 } | |
754 | |
8061 | 755 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) |
756 { | |
757 char *text; | |
758 GtkIMHtml *imhtml = data; | |
7809 | 759 |
8123 | 760 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml))) |
8105 | 761 return; |
762 | |
8061 | 763 if (selection_data->length < 0) { |
8931 | 764 gtk_clipboard_request_text(clipboard, paste_plaintext_received_cb, imhtml); |
765 return; | |
8061 | 766 } else { |
8719 | 767 #if 0 |
768 /* Here's some debug code, for figuring out what sent to us over the clipboard. */ | |
769 { | |
770 int i; | |
771 | |
772 gaim_debug_misc("gtkimhtml", "In paste_received_cb():\n\tformat = %d, length = %d\n\t", | |
773 selection_data->format, selection_data->length); | |
774 | |
775 for (i = 0; i < (/*(selection_data->format / 8) **/ selection_data->length); i++) { | |
776 if ((i % 70) == 0) | |
777 printf("\n\t"); | |
778 if (selection_data->data[i] == '\0') | |
779 printf("."); | |
780 else | |
781 printf("%c", selection_data->data[i]); | |
782 } | |
783 printf("\n"); | |
784 } | |
785 #endif | |
786 text = g_malloc(selection_data->length); | |
787 memcpy(text, selection_data->data, selection_data->length); | |
7766 | 788 } |
8061 | 789 |
8869 | 790 if (selection_data->length >= 2 && |
791 (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) { | |
792 /* This is UCS-2 */ | |
8909 | 793 char *tmp; |
8869 | 794 char *utf8 = g_convert(text, selection_data->length, "UTF-8", "UCS-2", NULL, NULL, NULL); |
8061 | 795 g_free(text); |
796 text = utf8; | |
8698 | 797 if (!text) { |
8869 | 798 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in paste_received_cb\n"); |
8698 | 799 return; |
800 } | |
8909 | 801 tmp = g_utf8_next_char(text); |
802 memmove(text, tmp, strlen(tmp) + 1); | |
8061 | 803 } |
8698 | 804 |
805 if (!(*text) || !g_utf8_validate(text, -1, NULL)) { | |
806 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in paste_received_cb\n"); | |
807 g_free(text); | |
808 return; | |
809 } | |
810 | |
8931 | 811 imhtml_paste_insert(imhtml, text, FALSE); |
8681 | 812 g_free(text); |
8061 | 813 } |
814 | |
815 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah) | |
816 { | |
8931 | 817 #ifdef _WIN32 |
818 /* If we're on windows, let's see if we can get data from the HTML Format | |
819 clipboard before we try to paste from the GTK buffer */ | |
820 HGLOBAL hdata; | |
821 DWORD err; | |
822 char *buffer; | |
823 char *text; | |
824 | |
825 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml))) | |
826 return; | |
827 | |
828 if (IsClipboardFormatAvailable(win_html_fmt)) { | |
829 OpenClipboard(NULL); | |
830 hdata = GetClipboardData(win_html_fmt); | |
831 if (hdata == NULL) { | |
832 err = GetLastError(); | |
833 gaim_debug_info("html clipboard", "error number %u! See http://msdn.microsoft.com/library/en-us/debug/base/system_error_codes.asp\n", err); | |
834 CloseClipboard(); | |
835 return; | |
836 } | |
837 buffer = GlobalLock(hdata); | |
838 if (buffer == NULL) { | |
839 err = GetLastError(); | |
840 gaim_debug_info("html clipboard", "error number %u! See http://msdn.microsoft.com/library/en-us/debug/base/system_error_codes.asp\n", err); | |
841 CloseClipboard(); | |
842 return; | |
843 } | |
844 text = clipboard_win32_to_html(buffer); | |
845 GlobalUnlock(hdata); | |
846 CloseClipboard(); | |
847 | |
848 imhtml_paste_insert(imhtml, text, FALSE); | |
849 g_free(text); | |
850 } else { | |
851 #endif | |
8061 | 852 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD); |
853 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE), | |
854 paste_received_cb, imhtml); | |
8931 | 855 #ifdef _WIN32 |
856 } | |
857 #endif | |
8061 | 858 g_signal_stop_emission_by_name(imhtml, "paste-clipboard"); |
7766 | 859 } |
860 | |
8677 | 861 static void imhtml_realized_remove_primary(GtkIMHtml *imhtml, gpointer unused) |
862 { | |
863 gtk_text_buffer_remove_selection_clipboard(GTK_IMHTML(imhtml)->text_buffer, | |
864 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY)); | |
865 | |
866 } | |
867 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
868 static void imhtml_destroy_add_primary(GtkIMHtml *imhtml, gpointer unused) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
869 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
870 gtk_text_buffer_add_selection_clipboard(GTK_IMHTML(imhtml)->text_buffer, |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
871 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
872 } |
8677 | 873 |
874 static void mark_set_so_update_selection_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml) | |
875 { | |
876 if (gtk_text_buffer_get_selection_bounds(buffer, NULL, NULL)) { | |
877 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY), | |
878 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
879 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
880 (GtkClipboardClearFunc)gtk_imhtml_primary_clipboard_clear, G_OBJECT(imhtml)); | |
881 } | |
882 } | |
883 | |
884 static gboolean gtk_imhtml_button_press_event(GtkIMHtml *imhtml, GdkEventButton *event, gpointer unused) | |
7346 | 885 { |
8677 | 886 if (event->button == 2) { |
887 int x, y; | |
888 GtkTextIter iter; | |
889 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY); | |
890 | |
891 if (!imhtml->editable) | |
892 return FALSE; | |
893 | |
894 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), | |
895 GTK_TEXT_WINDOW_TEXT, | |
896 event->x, | |
897 event->y, | |
898 &x, | |
899 &y); | |
900 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
901 gtk_text_buffer_place_cursor(imhtml->text_buffer, &iter); | |
902 | |
903 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE), | |
904 paste_received_cb, imhtml); | |
905 | |
906 return TRUE; | |
907 } | |
908 | |
7346 | 909 return FALSE; |
910 } | |
4263 | 911 |
4032 | 912 static GtkTextViewClass *parent_class = NULL; |
913 | |
914 static void | |
915 gtk_imhtml_finalize (GObject *object) | |
916 { | |
917 GtkIMHtml *imhtml = GTK_IMHTML(object); | |
4895 | 918 GList *scalables; |
8962 | 919 GSList *l; |
8061 | 920 |
4138 | 921 g_hash_table_destroy(imhtml->smiley_data); |
4032 | 922 gtk_smiley_tree_destroy(imhtml->default_smilies); |
4138 | 923 gdk_cursor_unref(imhtml->hand_cursor); |
924 gdk_cursor_unref(imhtml->arrow_cursor); | |
8061 | 925 gdk_cursor_unref(imhtml->text_cursor); |
8677 | 926 |
4735 | 927 if(imhtml->tip_window){ |
928 gtk_widget_destroy(imhtml->tip_window); | |
929 } | |
930 if(imhtml->tip_timer) | |
931 gtk_timeout_remove(imhtml->tip_timer); | |
932 | |
4895 | 933 for(scalables = imhtml->scalables; scalables; scalables = scalables->next) { |
934 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data); | |
935 scale->free(scale); | |
936 } | |
7991 | 937 |
8962 | 938 for (l = imhtml->im_images; l; l = l->next) { |
939 int id; | |
940 id = GPOINTER_TO_INT(l->data); | |
941 if (imhtml->funcs->image_unref) | |
942 imhtml->funcs->image_unref(id); | |
943 } | |
944 | |
8681 | 945 if (imhtml->clipboard_text_string) { |
946 g_free(imhtml->clipboard_text_string); | |
947 g_free(imhtml->clipboard_html_string); | |
948 } | |
949 | |
4895 | 950 g_list_free(imhtml->scalables); |
8962 | 951 g_slist_free(imhtml->im_images); |
9029 | 952 if (imhtml->protocol_name) |
953 g_free(imhtml->protocol_name); | |
4032 | 954 G_OBJECT_CLASS(parent_class)->finalize (object); |
955 } | |
1428 | 956 |
3922 | 957 /* Boring GTK stuff */ |
8519 | 958 static void gtk_imhtml_class_init (GtkIMHtmlClass *klass) |
1428 | 959 { |
9007 | 960 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; |
3922 | 961 GtkObjectClass *object_class; |
4032 | 962 GObjectClass *gobject_class; |
8519 | 963 object_class = (GtkObjectClass*) klass; |
964 gobject_class = (GObjectClass*) klass; | |
4032 | 965 parent_class = gtk_type_class(GTK_TYPE_TEXT_VIEW); |
4417 | 966 signals[URL_CLICKED] = g_signal_new("url_clicked", |
967 G_TYPE_FROM_CLASS(gobject_class), | |
968 G_SIGNAL_RUN_FIRST, | |
969 G_STRUCT_OFFSET(GtkIMHtmlClass, url_clicked), | |
970 NULL, | |
971 0, | |
972 g_cclosure_marshal_VOID__POINTER, | |
973 G_TYPE_NONE, 1, | |
974 G_TYPE_POINTER); | |
8506 | 975 signals[BUTTONS_UPDATE] = g_signal_new("format_buttons_update", |
8420 | 976 G_TYPE_FROM_CLASS(gobject_class), |
977 G_SIGNAL_RUN_FIRST, | |
978 G_STRUCT_OFFSET(GtkIMHtmlClass, buttons_update), | |
979 NULL, | |
980 0, | |
981 g_cclosure_marshal_VOID__POINTER, | |
982 G_TYPE_NONE, 1, | |
983 G_TYPE_INT); | |
984 signals[TOGGLE_FORMAT] = g_signal_new("format_function_toggle", | |
985 G_TYPE_FROM_CLASS(gobject_class), | |
986 G_SIGNAL_RUN_FIRST, | |
987 G_STRUCT_OFFSET(GtkIMHtmlClass, toggle_format), | |
988 NULL, | |
989 0, | |
990 g_cclosure_marshal_VOID__POINTER, | |
8427 | 991 G_TYPE_NONE, 1, |
8420 | 992 G_TYPE_INT); |
8427 | 993 signals[CLEAR_FORMAT] = g_signal_new("format_function_clear", |
994 G_TYPE_FROM_CLASS(gobject_class), | |
995 G_SIGNAL_RUN_FIRST, | |
996 G_STRUCT_OFFSET(GtkIMHtmlClass, clear_format), | |
997 NULL, | |
998 0, | |
8481 | 999 g_cclosure_marshal_VOID__VOID, |
1000 G_TYPE_NONE, 0); | |
8506 | 1001 signals[UPDATE_FORMAT] = g_signal_new("format_function_update", |
1002 G_TYPE_FROM_CLASS(gobject_class), | |
1003 G_SIGNAL_RUN_FIRST, | |
1004 G_STRUCT_OFFSET(GtkIMHtmlClass, update_format), | |
1005 NULL, | |
1006 0, | |
1007 g_cclosure_marshal_VOID__VOID, | |
1008 G_TYPE_NONE, 0); | |
4032 | 1009 gobject_class->finalize = gtk_imhtml_finalize; |
9300 | 1010 widget_class->drag_motion = gtk_text_view_drag_motion; |
9007 | 1011 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("hyperlink-color", |
1012 _("Hyperlink color"), | |
1013 _("Color to draw hyperlinks."), | |
1014 GDK_TYPE_COLOR, G_PARAM_READABLE)); | |
1428 | 1015 } |
1016 | |
3922 | 1017 static void gtk_imhtml_init (GtkIMHtml *imhtml) |
1428 | 1018 { |
3922 | 1019 GtkTextIter iter; |
1020 imhtml->text_buffer = gtk_text_buffer_new(NULL); | |
1021 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); | |
8677 | 1022 imhtml->scrollpoint = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); |
3922 | 1023 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); |
5105 | 1024 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); |
3922 | 1025 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); |
8677 | 1026 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(imhtml), 2); |
1027 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(imhtml), 2); | |
8061 | 1028 /*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/ |
3922 | 1029 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ |
8061 | 1030 |
3922 | 1031 /* These tags will be used often and can be reused--we create them on init and then apply them by name |
8932 | 1032 * other tags (color, size, face, etc.) will have to be created and applied dynamically |
1033 * Note that even though we created STRIKE, SUB, SUP, and PRE tags here, we don't really | |
1034 * apply them anywhere yet. */ | |
3922 | 1035 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); |
1036 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); | |
1037 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); | |
1038 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); | |
1039 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); | |
1040 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); | |
1041 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); | |
7295 | 1042 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); |
8677 | 1043 |
3922 | 1044 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ |
1045 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); | |
1046 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); | |
8061 | 1047 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); |
2993 | 1048 |
6124 | 1049 imhtml->show_comments = TRUE; |
4253 | 1050 |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
1051 imhtml->zoom = 1.0; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
1052 imhtml->original_fsize = 0; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
1053 |
4892 | 1054 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 1055 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4032 | 1056 imhtml->default_smilies = gtk_smiley_tree_new(); |
4735 | 1057 |
4944 | 1058 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL); |
4735 | 1059 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); |
4944 | 1060 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); |
6066 | 1061 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); |
8677 | 1062 g_signal_connect(G_OBJECT(imhtml), "button_press_event", G_CALLBACK(gtk_imhtml_button_press_event), NULL); |
1063 g_signal_connect(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(preinsert_cb), imhtml); | |
8061 | 1064 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); |
8091 | 1065 gtk_drag_dest_set(GTK_WIDGET(imhtml), 0, |
1066 link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry), | |
1067 GDK_ACTION_COPY); | |
1068 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml); | |
9300 | 1069 g_signal_connect(G_OBJECT(imhtml), "drag_drop", G_CALLBACK(gtk_imhtml_link_drop_cb), imhtml); |
8091 | 1070 |
7353 | 1071 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); |
8698 | 1072 g_signal_connect(G_OBJECT(imhtml), "cut-clipboard", G_CALLBACK(cut_clipboard_cb), NULL); |
8061 | 1073 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL); |
8677 | 1074 g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL); |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
1075 g_signal_connect(G_OBJECT(imhtml), "unrealize", G_CALLBACK(imhtml_destroy_add_primary), NULL); |
8677 | 1076 |
1077 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set", | |
1078 G_CALLBACK(mark_set_so_update_selection_cb), imhtml); | |
1079 | |
4944 | 1080 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); |
4735 | 1081 |
8681 | 1082 imhtml->clipboard_text_string = NULL; |
1083 imhtml->clipboard_html_string = NULL; | |
1084 | |
4735 | 1085 imhtml->tip = NULL; |
1086 imhtml->tip_timer = 0; | |
1087 imhtml->tip_window = NULL; | |
4895 | 1088 |
8677 | 1089 imhtml->edit.bold = FALSE; |
1090 imhtml->edit.italic = FALSE; | |
1091 imhtml->edit.underline = FALSE; | |
8061 | 1092 imhtml->edit.forecolor = NULL; |
1093 imhtml->edit.backcolor = NULL; | |
1094 imhtml->edit.fontface = NULL; | |
8677 | 1095 imhtml->edit.fontsize = 0; |
1096 imhtml->edit.link = NULL; | |
1097 | |
9300 | 1098 |
4895 | 1099 imhtml->scalables = NULL; |
8061 | 1100 |
1101 gtk_imhtml_set_editable(imhtml, FALSE); | |
8931 | 1102 g_signal_connect(G_OBJECT(imhtml), "populate-popup", |
1103 G_CALLBACK(hijack_menu_cb), NULL); | |
1104 | |
8692 | 1105 #ifdef _WIN32 |
1106 /* Register HTML Format as desired clipboard format */ | |
1107 win_html_fmt = RegisterClipboardFormat("HTML Format"); | |
1108 #endif | |
2993 | 1109 } |
1110 | |
3922 | 1111 GtkWidget *gtk_imhtml_new(void *a, void *b) |
1428 | 1112 { |
4635 | 1113 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); |
1428 | 1114 } |
1115 | |
9037 | 1116 GType gtk_imhtml_get_type() |
1428 | 1117 { |
9037 | 1118 static GType imhtml_type = 0; |
1428 | 1119 |
1120 if (!imhtml_type) { | |
9037 | 1121 static const GTypeInfo imhtml_info = { |
4635 | 1122 sizeof(GtkIMHtmlClass), |
1123 NULL, | |
1124 NULL, | |
1125 (GClassInitFunc) gtk_imhtml_class_init, | |
1126 NULL, | |
1127 NULL, | |
1428 | 1128 sizeof (GtkIMHtml), |
4635 | 1129 0, |
1130 (GInstanceInitFunc) gtk_imhtml_init | |
1428 | 1131 }; |
4635 | 1132 |
1133 imhtml_type = g_type_register_static(gtk_text_view_get_type(), | |
1134 "GtkIMHtml", &imhtml_info, 0); | |
1428 | 1135 } |
1136 | |
1137 return imhtml_type; | |
1138 } | |
1139 | |
4417 | 1140 struct url_data { |
1141 GObject *object; | |
1142 gchar *url; | |
1143 }; | |
1144 | |
8677 | 1145 static void url_data_destroy(gpointer mydata) |
1146 { | |
1147 struct url_data *data = mydata; | |
1148 g_object_unref(data->object); | |
1149 g_free(data->url); | |
1150 g_free(data); | |
1151 } | |
1152 | |
4417 | 1153 static void url_open(GtkWidget *w, struct url_data *data) { |
1154 if(!data) return; | |
8061 | 1155 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); |
7988 | 1156 |
4417 | 1157 } |
5582 | 1158 |
4417 | 1159 static void url_copy(GtkWidget *w, gchar *url) { |
1160 GtkClipboard *clipboard; | |
1161 | |
8931 | 1162 clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_PRIMARY); |
4417 | 1163 gtk_clipboard_set_text(clipboard, url, -1); |
5582 | 1164 |
8931 | 1165 clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_CLIPBOARD); |
5582 | 1166 gtk_clipboard_set_text(clipboard, url, -1); |
4417 | 1167 } |
1168 | |
1169 /* The callback for an event on a link tag. */ | |
8677 | 1170 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, gpointer unused) { |
4417 | 1171 GdkEventButton *event_button = (GdkEventButton *) event; |
8061 | 1172 if (GTK_IMHTML(imhtml)->editable) |
1173 return FALSE; | |
3922 | 1174 if (event->type == GDK_BUTTON_RELEASE) { |
8957 | 1175 if ((event_button->button == 1) || (event_button->button == 2)) { |
4417 | 1176 GtkTextIter start, end; |
1177 /* we shouldn't open a URL if the user has selected something: */ | |
8677 | 1178 if (gtk_text_buffer_get_selection_bounds( |
1179 gtk_text_iter_get_buffer(arg2), &start, &end)) | |
4417 | 1180 return FALSE; |
1181 | |
1182 /* A link was clicked--we emit the "url_clicked" signal | |
1183 * with the URL as the argument */ | |
8677 | 1184 g_object_ref(G_OBJECT(tag)); |
1185 g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url")); | |
1186 g_object_unref(G_OBJECT(tag)); | |
4417 | 1187 return FALSE; |
1188 } else if(event_button->button == 3) { | |
4745 | 1189 GtkWidget *img, *item, *menu; |
4417 | 1190 struct url_data *tempdata = g_new(struct url_data, 1); |
5091 | 1191 tempdata->object = g_object_ref(imhtml); |
8677 | 1192 tempdata->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url")); |
4745 | 1193 |
5091 | 1194 /* Don't want the tooltip around if user right-clicked on link */ |
1195 if (GTK_IMHTML(imhtml)->tip_window) { | |
1196 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
1197 GTK_IMHTML(imhtml)->tip_window = NULL; | |
1198 } | |
1199 if (GTK_IMHTML(imhtml)->tip_timer) { | |
1200 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
1201 GTK_IMHTML(imhtml)->tip_timer = 0; | |
1202 } | |
8061 | 1203 if (GTK_IMHTML(imhtml)->editable) |
1204 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor); | |
1205 else | |
1206 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
4417 | 1207 menu = gtk_menu_new(); |
8677 | 1208 g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", tempdata, url_data_destroy); |
4745 | 1209 |
4417 | 1210 /* buttons and such */ |
1211 | |
8677 | 1212 if (!strncmp(tempdata->url, "mailto:", 7)) |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1213 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1214 /* Copy E-Mail Address */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1215 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1216 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1217 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1218 _("_Copy E-Mail Address")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1219 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1220 g_signal_connect(G_OBJECT(item), "activate", |
8677 | 1221 G_CALLBACK(url_copy), tempdata->url + 7); |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1222 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1223 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1224 else |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1225 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1226 /* Copy Link Location */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1227 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1228 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1229 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1230 _("_Copy Link Location")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1231 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1232 g_signal_connect(G_OBJECT(item), "activate", |
8677 | 1233 G_CALLBACK(url_copy), tempdata->url); |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1234 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1235 |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1236 /* Open Link in Browser */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1237 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1238 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1239 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1240 _("_Open Link in Browser")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1241 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1242 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1243 G_CALLBACK(url_open), tempdata); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1244 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1245 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1246 |
4756 | 1247 |
4417 | 1248 gtk_widget_show_all(menu); |
4756 | 1249 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
1250 event_button->button, event_button->time); | |
4745 | 1251 |
4417 | 1252 return TRUE; |
1253 } | |
1428 | 1254 } |
4417 | 1255 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) |
1256 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
1257 be caught by the regular GtkTextView menu */ | |
1258 else | |
1259 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
1428 | 1260 } |
1261 | |
9300 | 1262 static gboolean |
1263 gtk_text_view_drag_motion (GtkWidget *widget, | |
1264 GdkDragContext *context, | |
1265 gint x, | |
1266 gint y, | |
1267 guint time) | |
1268 { | |
1269 GdkDragAction suggested_action = 0; | |
1270 | |
1271 if (gtk_drag_dest_find_target (widget, context, | |
1272 gtk_drag_dest_get_target_list (widget)) == GDK_NONE) { | |
1273 /* can't accept any of the offered targets */ | |
1274 } else { | |
1275 GtkWidget *source_widget; | |
1276 suggested_action = context->suggested_action; | |
1277 source_widget = gtk_drag_get_source_widget (context); | |
1278 if (source_widget == widget) { | |
1279 /* Default to MOVE, unless the user has | |
1280 * pressed ctrl or alt to affect available actions | |
1281 */ | |
1282 if ((context->actions & GDK_ACTION_MOVE) != 0) | |
1283 suggested_action = GDK_ACTION_MOVE; | |
1284 } | |
1285 } | |
1286 | |
1287 if (suggested_action != 0) { | |
1288 gdk_drag_status (context, suggested_action, time); | |
1289 } else { | |
1290 gdk_drag_status (context, 0, time); | |
1291 } | |
1292 | |
1293 /* TRUE return means don't propagate the drag motion to parent | |
1294 * widgets that may also be drop sites. | |
1295 */ | |
1296 return TRUE; | |
1297 } | |
1298 | |
1299 static void | |
1300 gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data) | |
1301 { | |
1302 GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL); | |
1303 | |
1304 if (target != GDK_NONE) | |
1305 gtk_drag_get_data (widget, context, target, time); | |
1306 else | |
1307 gtk_drag_finish (context, FALSE, FALSE, time); | |
1308 | |
1309 return; | |
1310 } | |
1311 | |
8091 | 1312 static void |
1313 gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, | |
1314 GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml) | |
1315 { | |
9300 | 1316 gchar **links; |
1317 gchar *link; | |
1318 char *text = sd->data; | |
1319 GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
1320 GtkTextIter iter; | |
1321 | |
1322 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
1323 | |
1324 | |
8091 | 1325 if(gtk_imhtml_get_editable(imhtml) && sd->data){ |
9300 | 1326 switch (info) { |
1327 case DRAG_URL: | |
1328 gaim_str_strip_cr(sd->data); | |
1329 | |
1330 links = g_strsplit(sd->data, "\n", 0); | |
1331 while((link = *links++) != NULL){ | |
1332 if(gaim_str_has_prefix(link, "http://") || | |
1333 gaim_str_has_prefix(link, "https://") || | |
1334 gaim_str_has_prefix(link, "ftp://")){ | |
1335 gtk_imhtml_insert_link(imhtml, mark, link, link); | |
1336 } else if (link=='\0') { | |
1337 /* Ignore blank lines */ | |
1338 } else { | |
1339 /* Special reasons, aka images being put in via other tag, etc. */ | |
1340 } | |
8091 | 1341 } |
9300 | 1342 break; |
1343 case DRAG_HTML: | |
1344 if (sd->length >= 2 && | |
1345 (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) { | |
1346 /* This is UCS-2 */ | |
1347 char *tmp; | |
1348 char *utf8 = g_convert(text, sd->length, "UTF-8", "UCS-2", NULL, NULL, NULL); | |
1349 g_free(text); | |
1350 text = utf8; | |
1351 if (!text) { | |
1352 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in drag_rcv_cb\n"); | |
1353 return; | |
1354 } | |
1355 tmp = g_utf8_next_char(text); | |
1356 memmove(text, tmp, strlen(tmp) + 1); | |
1357 } | |
1358 | |
1359 if (!(*text) || !g_utf8_validate(text, -1, NULL)) { | |
1360 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n"); | |
1361 g_free(text); | |
1362 return; | |
1363 } | |
1364 gtk_imhtml_insert_html_at_iter(imhtml, text, 0, &iter); | |
1365 break; | |
1366 default: | |
1367 break; | |
8091 | 1368 } |
9300 | 1369 |
1370 | |
8091 | 1371 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); |
1372 } else { | |
1373 gtk_drag_finish(dc, FALSE, FALSE, t); | |
1374 } | |
1375 } | |
1376 | |
4298 | 1377 /* this isn't used yet |
9300 | 1378 static void gtk_smiley_tree_remove (GtkSmileyTree *tree, |
4263 | 1379 GtkIMHtmlSmiley *smiley) |
4032 | 1380 { |
1381 GtkSmileyTree *t = tree; | |
4263 | 1382 const gchar *x = smiley->smile; |
4032 | 1383 gint len = 0; |
1384 | |
1385 while (*x) { | |
1386 gchar *pos; | |
1387 | |
1388 if (!t->values) | |
1389 return; | |
1390 | |
1391 pos = strchr (t->values->str, *x); | |
1392 if (pos) | |
1393 t = t->children [(int) pos - (int) t->values->str]; | |
1394 else | |
1395 return; | |
1396 | |
1397 x++; len++; | |
1398 } | |
1399 | |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1400 if (t->image) { |
4032 | 1401 t->image = NULL; |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1402 } |
4032 | 1403 } |
4298 | 1404 */ |
1405 | |
4032 | 1406 |
1407 static gint | |
1408 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
1409 const gchar *text) | |
1410 { | |
1411 GtkSmileyTree *t = tree; | |
1412 const gchar *x = text; | |
1413 gint len = 0; | |
8505 | 1414 gchar *amp; |
1415 gint alen; | |
4032 | 1416 |
1417 while (*x) { | |
1418 gchar *pos; | |
1419 | |
1420 if (!t->values) | |
1421 break; | |
1422 | |
8505 | 1423 if(*x == '&' && gtk_imhtml_is_amp_escape(x, &, &alen)) { |
1424 len += alen - strlen(amp); | |
1425 x += alen - strlen(amp); | |
1426 pos = strchr (t->values->str, *amp); | |
1427 } | |
1428 else | |
1429 pos = strchr (t->values->str, *x); | |
1430 | |
4032 | 1431 if (pos) |
7371 | 1432 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1433 else |
1434 break; | |
1435 | |
1436 x++; len++; | |
1437 } | |
1438 | |
1439 if (t->image) | |
1440 return len; | |
1441 | |
1442 return 0; | |
1443 } | |
1444 | |
1445 void | |
4263 | 1446 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
1447 gchar *sml, | |
1448 GtkIMHtmlSmiley *smiley) | |
4032 | 1449 { |
1450 GtkSmileyTree *tree; | |
1451 g_return_if_fail (imhtml != NULL); | |
1452 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
7371 | 1453 |
4032 | 1454 if (sml == NULL) |
1455 tree = imhtml->default_smilies; | |
1456 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
1457 } else { | |
1458 tree = gtk_smiley_tree_new(); | |
4892 | 1459 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
4032 | 1460 } |
1461 | |
4263 | 1462 gtk_smiley_tree_insert (tree, smiley); |
4032 | 1463 } |
1464 | |
1465 static gboolean | |
1466 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
1467 GSList *fonts, | |
1468 const gchar *text, | |
1469 gint *len) | |
1470 { | |
1471 GtkSmileyTree *tree; | |
5967 | 1472 GtkIMHtmlFontDetail *font; |
4032 | 1473 char *sml = NULL; |
1474 | |
1475 if (fonts) { | |
1476 font = fonts->data; | |
1477 sml = font->sml; | |
1478 } | |
1479 | |
9029 | 1480 if (!sml) |
1481 sml = imhtml->protocol_name; | |
1482 | |
1483 if (!sml || !(tree = g_hash_table_lookup(imhtml->smiley_data, sml))) | |
4032 | 1484 tree = imhtml->default_smilies; |
9029 | 1485 |
4032 | 1486 if (tree == NULL) |
1487 return FALSE; | |
7371 | 1488 |
8505 | 1489 *len = gtk_smiley_tree_lookup (tree, text); |
4032 | 1490 return (*len > 0); |
1491 } | |
1492 | |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1493 GdkPixbufAnimation * |
4032 | 1494 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
1495 const gchar *sml, | |
1496 const gchar *text) | |
1497 { | |
1498 GtkSmileyTree *t; | |
1499 const gchar *x = text; | |
1500 if (sml == NULL) | |
1501 t = imhtml->default_smilies; | |
7371 | 1502 else |
4032 | 1503 t = g_hash_table_lookup(imhtml->smiley_data, sml); |
7371 | 1504 |
4032 | 1505 |
1506 if (t == NULL) | |
1507 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1508 | |
1509 while (*x) { | |
1510 gchar *pos; | |
1511 | |
1512 if (!t->values) { | |
1513 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1514 } | |
7371 | 1515 |
4032 | 1516 pos = strchr (t->values->str, *x); |
1517 if (pos) { | |
7371 | 1518 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1519 } else { |
1520 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1521 } | |
1522 x++; | |
1523 } | |
1524 | |
8890 | 1525 if (!t->image->file) |
1526 return NULL; | |
1527 | |
4263 | 1528 if (!t->image->icon) |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1529 t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); |
4263 | 1530 |
1531 return t->image->icon; | |
4032 | 1532 } |
8890 | 1533 |
4793 | 1534 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
3922 | 1535 *tag = g_strndup (string, strlen (x)); \ |
1536 *len = strlen (x) + 1; \ | |
1537 return TRUE; \ | |
1538 } \ | |
1539 (*type)++ | |
1428 | 1540 |
4793 | 1541 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
3922 | 1542 const gchar *c = string + strlen (x " "); \ |
1543 gchar e = '"'; \ | |
1544 gboolean quote = FALSE; \ | |
1545 while (*c) { \ | |
1546 if (*c == '"' || *c == '\'') { \ | |
1547 if (quote && (*c == e)) \ | |
1548 quote = !quote; \ | |
1549 else if (!quote) { \ | |
1550 quote = !quote; \ | |
1551 e = *c; \ | |
1552 } \ | |
1553 } else if (!quote && (*c == '>')) \ | |
1554 break; \ | |
1555 c++; \ | |
1556 } \ | |
1557 if (*c) { \ | |
1558 *tag = g_strndup (string, c - string); \ | |
1559 *len = c - string + 1; \ | |
1560 return TRUE; \ | |
1561 } \ | |
1562 } \ | |
1563 (*type)++ | |
1428 | 1564 |
1565 | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1566 static gboolean |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1567 gtk_imhtml_is_amp_escape (const gchar *string, |
7280 | 1568 gchar **replace, |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1569 gint *length) |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1570 { |
7287 | 1571 static char buf[7]; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1572 g_return_val_if_fail (string != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1573 g_return_val_if_fail (replace != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1574 g_return_val_if_fail (length != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1575 |
4793 | 1576 if (!g_ascii_strncasecmp (string, "&", 5)) { |
7280 | 1577 *replace = "&"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1578 *length = 5; |
4793 | 1579 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
7280 | 1580 *replace = "<"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1581 *length = 4; |
4793 | 1582 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
7280 | 1583 *replace = ">"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1584 *length = 4; |
4793 | 1585 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
7280 | 1586 *replace = " "; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1587 *length = 6; |
4793 | 1588 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
7280 | 1589 *replace = "©"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1590 *length = 6; |
4793 | 1591 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
7280 | 1592 *replace = "\""; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1593 *length = 6; |
4793 | 1594 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
7280 | 1595 *replace = "®"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1596 *length = 5; |
5093 | 1597 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
7280 | 1598 *replace = "\'"; |
5093 | 1599 *length = 6; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1600 } else if (*(string + 1) == '#') { |
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
1601 guint pound = 0; |
3004 | 1602 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
7287 | 1603 int buflen; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1604 if (*(string + 3 + (gint)log10 (pound)) != ';') |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1605 return FALSE; |
7287 | 1606 buflen = g_unichar_to_utf8((gunichar)pound, buf); |
1607 buf[buflen] = '\0'; | |
7280 | 1608 *replace = buf; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1609 *length = 2; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1610 while (isdigit ((gint) string [*length])) (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1611 if (string [*length] == ';') (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1612 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1613 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1614 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1615 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1616 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1617 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1618 |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1619 return TRUE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1620 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1621 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1622 static gboolean |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1623 gtk_imhtml_is_tag (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1624 gchar **tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1625 gint *len, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1626 gint *type) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1627 { |
8061 | 1628 char *close; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1629 *type = 1; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1630 |
8118 | 1631 |
8061 | 1632 if (!(close = strchr (string, '>'))) |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1633 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1634 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1635 VALID_TAG ("B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1636 VALID_TAG ("BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1637 VALID_TAG ("/B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1638 VALID_TAG ("/BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1639 VALID_TAG ("I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1640 VALID_TAG ("ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1641 VALID_TAG ("/I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1642 VALID_TAG ("/ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1643 VALID_TAG ("U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1644 VALID_TAG ("UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1645 VALID_TAG ("/U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1646 VALID_TAG ("/UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1647 VALID_TAG ("S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1648 VALID_TAG ("STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1649 VALID_TAG ("/S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1650 VALID_TAG ("/STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1651 VALID_TAG ("SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1652 VALID_TAG ("/SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1653 VALID_TAG ("SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1654 VALID_TAG ("/SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1655 VALID_TAG ("PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1656 VALID_TAG ("/PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1657 VALID_TAG ("TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1658 VALID_TAG ("/TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1659 VALID_TAG ("BR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1660 VALID_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1661 VALID_TAG ("/FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1662 VALID_TAG ("/A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1663 VALID_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1664 VALID_TAG ("/P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1665 VALID_TAG ("H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1666 VALID_TAG ("/H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1667 VALID_TAG ("HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1668 VALID_TAG ("/HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1669 VALID_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1670 VALID_TAG ("/BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1671 VALID_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1672 VALID_TAG ("HEAD"); |
2993 | 1673 VALID_TAG ("/HEAD"); |
1674 VALID_TAG ("BINARY"); | |
1675 VALID_TAG ("/BINARY"); | |
5093 | 1676 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1677 VALID_OPT_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1678 VALID_OPT_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1679 VALID_OPT_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1680 VALID_OPT_TAG ("A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1681 VALID_OPT_TAG ("IMG"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1682 VALID_OPT_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1683 VALID_OPT_TAG ("H3"); |
5093 | 1684 VALID_OPT_TAG ("HTML"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1685 |
5101 | 1686 VALID_TAG ("CITE"); |
1687 VALID_TAG ("/CITE"); | |
1688 VALID_TAG ("EM"); | |
1689 VALID_TAG ("/EM"); | |
1690 VALID_TAG ("STRONG"); | |
1691 VALID_TAG ("/STRONG"); | |
1692 | |
5104 | 1693 VALID_OPT_TAG ("SPAN"); |
1694 VALID_TAG ("/SPAN"); | |
5174 | 1695 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
6982 | 1696 VALID_TAG ("IMG"); |
8026 | 1697 VALID_TAG("SPAN"); |
8061 | 1698 VALID_OPT_TAG("BR"); |
7988 | 1699 |
4793 | 1700 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
1701 gchar *e = strstr (string + strlen("!--"), "-->"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1702 if (e) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1703 *len = e - string + strlen ("-->"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1704 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1705 return TRUE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1706 } |
8118 | 1707 } |
1708 | |
8061 | 1709 *type = -1; |
1710 *len = close - string + 1; | |
1711 *tag = g_strndup(string, *len - 1); | |
1712 return TRUE; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1713 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1714 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1715 static gchar* |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1716 gtk_imhtml_get_html_opt (gchar *tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1717 const gchar *opt) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1718 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1719 gchar *t = tag; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1720 gchar *e, *a; |
5177 | 1721 gchar *val; |
1722 gint len; | |
7280 | 1723 gchar *c; |
5177 | 1724 GString *ret; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1725 |
4793 | 1726 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1727 gboolean quote = FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1728 if (*t == '\0') break; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1729 while (*t && !((*t == ' ') && !quote)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1730 if (*t == '\"') |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1731 quote = ! quote; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1732 t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1733 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1734 while (*t && (*t == ' ')) t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1735 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1736 |
4793 | 1737 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1738 t += strlen (opt); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1739 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1740 return NULL; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1741 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1742 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1743 if ((*t == '\"') || (*t == '\'')) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1744 e = a = ++t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1745 while (*e && (*e != *(t - 1))) e++; |
2993 | 1746 if (*e == '\0') { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1747 return NULL; |
5177 | 1748 } else |
1749 val = g_strndup(a, e - a); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1750 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1751 e = a = t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1752 while (*e && !isspace ((gint) *e)) e++; |
5177 | 1753 val = g_strndup(a, e - a); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1754 } |
5177 | 1755 |
1756 ret = g_string_new(""); | |
1757 e = val; | |
1758 while(*e) { | |
1759 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
7280 | 1760 ret = g_string_append(ret, c); |
5177 | 1761 e += len; |
1762 } else { | |
1763 ret = g_string_append_c(ret, *e); | |
1764 e++; | |
1765 } | |
1766 } | |
1767 | |
1768 g_free(val); | |
8568 | 1769 |
1770 return g_string_free(ret, FALSE); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1771 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1772 |
8118 | 1773 /* Inline CSS Support - Douglas Thrift */ |
1774 static gchar* | |
1775 gtk_imhtml_get_css_opt (gchar *style, | |
1776 const gchar *opt) | |
1777 { | |
1778 gchar *t = style; | |
1779 gchar *e, *a; | |
1780 gchar *val; | |
1781 gint len; | |
1782 gchar *c; | |
1783 GString *ret; | |
1784 | |
1785 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
8177 | 1786 /* gboolean quote = FALSE; */ |
8118 | 1787 if (*t == '\0') break; |
1788 while (*t && !((*t == ' ') /*&& !quote*/)) { | |
1789 /* if (*t == '\"') | |
8177 | 1790 quote = ! quote; */ |
8118 | 1791 t++; |
1792 } | |
1793 while (*t && (*t == ' ')) t++; | |
1794 } | |
1795 | |
1796 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
1797 t += strlen (opt); | |
1798 } else { | |
1799 return NULL; | |
1800 } | |
1801 | |
1802 /* if ((*t == '\"') || (*t == '\'')) { | |
1803 e = a = ++t; | |
1804 while (*e && (*e != *(t - 1))) e++; | |
1805 if (*e == '\0') { | |
1806 return NULL; | |
1807 } else | |
1808 val = g_strndup(a, e - a); | |
1809 } else { | |
1810 e = a = t; | |
1811 while (*e && !isspace ((gint) *e)) e++; | |
1812 val = g_strndup(a, e - a); | |
1813 }*/ | |
1814 | |
1815 e = a = t; | |
1816 while (*e && *e != ';') e++; | |
1817 val = g_strndup(a, e - a); | |
1818 | |
1819 ret = g_string_new(""); | |
1820 e = val; | |
1821 while(*e) { | |
1822 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
1823 ret = g_string_append(ret, c); | |
1824 e += len; | |
1825 } else { | |
1826 ret = g_string_append_c(ret, *e); | |
1827 e++; | |
1828 } | |
1829 } | |
1830 | |
1831 g_free(val); | |
1832 val = ret->str; | |
1833 g_string_free(ret, FALSE); | |
1834 return val; | |
1835 } | |
3922 | 1836 |
8334 | 1837 static const char *accepted_protocols[] = { |
1838 "http://", | |
1839 "https://", | |
1840 "ftp://" | |
1841 }; | |
1842 | |
1843 static const int accepted_protocols_size = 3; | |
1844 | |
1845 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so | |
1846 the caller knows how long the protocol string is. */ | |
1847 int gtk_imhtml_is_protocol(const char *text) | |
1848 { | |
1849 gint i; | |
1850 | |
1851 for(i=0; i<accepted_protocols_size; i++){ | |
1852 if( strncasecmp(text, accepted_protocols[i], strlen(accepted_protocols[i])) == 0 ){ | |
1853 return strlen(accepted_protocols[i]); | |
1854 } | |
1855 } | |
1856 return 0; | |
1857 } | |
1858 | |
8677 | 1859 /* |
1860 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming | |
1861 | |
1862 | |
1863 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :) | |
1864 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/> | |
1865 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz | |
1866 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add | |
1867 [20:00] <marv> Robot101: so how does the image get passed to serv_got_im() and serv_send_im()? just as the <img id="#" and then the prpl looks it up from the store? | |
1868 [20:00] <KingAnt> marv: Right | |
1869 [20:00] <marv> alright | |
1870 | |
1871 Here's my plan with IMImages. make gtk_imhtml_[append|insert]_text_with_images instead just | |
1872 gtkimhtml_[append|insert]_text (hrm maybe it should be called html instead of text), add a | |
1873 function for gaim to register for look up images, i.e. gtk_imhtml_set_get_img_fnc, so that | |
1874 images can be looked up like that, instead of passing a GSList of them. | |
1875 */ | |
1876 | |
1877 void gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, | |
1878 const gchar *text, | |
1879 GtkIMHtmlOptions options, | |
1880 GSList *unused) | |
1428 | 1881 { |
8677 | 1882 GtkTextIter iter, ins, sel; |
1883 GdkRectangle rect; | |
1884 int y, height, ins_offset = 0, sel_offset = 0; | |
1885 gboolean fixins = FALSE, fixsel = FALSE; | |
1886 | |
1887 g_return_if_fail (imhtml != NULL); | |
1888 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1889 g_return_if_fail (text != NULL); | |
1890 | |
1891 | |
1892 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1893 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, gtk_text_buffer_get_insert(imhtml->text_buffer)); | |
1894 if (gtk_text_iter_equal(&iter, &ins) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1895 fixins = TRUE; | |
1896 ins_offset = gtk_text_iter_get_offset(&ins); | |
1897 } | |
1898 | |
1899 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &sel, gtk_text_buffer_get_selection_bound(imhtml->text_buffer)); | |
1900 if (gtk_text_iter_equal(&iter, &sel) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1901 fixsel = TRUE; | |
1902 sel_offset = gtk_text_iter_get_offset(&sel); | |
1903 } | |
1904 | |
1905 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1906 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); | |
1907 | |
1908 | |
1909 if(((y + height) - (rect.y + rect.height)) > height | |
1910 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ | |
1911 options |= GTK_IMHTML_NO_SCROLL; | |
1912 } | |
1913 | |
1914 gtk_imhtml_insert_html_at_iter(imhtml, text, options, &iter); | |
1915 | |
1916 if (fixins) { | |
1917 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins, ins_offset); | |
1918 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_insert(imhtml->text_buffer), &ins); | |
1919 } | |
1920 | |
1921 if (fixsel) { | |
1922 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &sel, sel_offset); | |
1923 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_selection_bound(imhtml->text_buffer), &sel); | |
1924 } | |
1925 | |
1926 if (!(options & GTK_IMHTML_NO_SCROLL)) { | |
8729 | 1927 gtk_imhtml_scroll_to_end(imhtml); |
8677 | 1928 } |
1929 } | |
1930 | |
8729 | 1931 void gtk_imhtml_scroll_to_end(GtkIMHtml *imhtml) |
1932 { | |
1933 GtkTextIter iter; | |
1934 /* If this seems backwards at first glance, well it's not. | |
1935 * It means scroll such that the mark is closest to the top, | |
1936 * and closest to the right as possible. Remember kids, you have | |
1937 * to scroll left to move a given spot closest to the right, | |
1938 * and scroll down to move a spot closest to the top. | |
1939 */ | |
1940 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1941 gtk_text_iter_set_line_offset(&iter, 0); | |
1942 gtk_text_buffer_move_mark(imhtml->text_buffer, imhtml->scrollpoint, &iter); | |
1943 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), imhtml->scrollpoint, | |
1944 0, TRUE, 1.0, 0.0); | |
1945 } | |
1946 | |
8677 | 1947 void gtk_imhtml_insert_html_at_iter(GtkIMHtml *imhtml, |
1948 const gchar *text, | |
1949 GtkIMHtmlOptions options, | |
1950 GtkTextIter *iter) | |
1951 { | |
8061 | 1952 GdkRectangle rect; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1953 gint pos = 0; |
3922 | 1954 gchar *ws; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1955 gchar *tag; |
3922 | 1956 gchar *bg = NULL; |
6982 | 1957 gint len; |
4032 | 1958 gint tlen, smilelen, wpos=0; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1959 gint type; |
3922 | 1960 const gchar *c; |
7280 | 1961 gchar *amp; |
8334 | 1962 gint len_protocol; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1963 |
1428 | 1964 guint bold = 0, |
1965 italics = 0, | |
1966 underline = 0, | |
1967 strike = 0, | |
1968 sub = 0, | |
1969 sup = 0, | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1970 title = 0, |
8061 | 1971 pre = 0; |
1428 | 1972 |
3922 | 1973 GSList *fonts = NULL; |
8506 | 1974 GObject *object; |
8061 | 1975 GtkIMHtmlScalable *scalable = NULL; |
8677 | 1976 |
1977 g_return_if_fail (imhtml != NULL); | |
1978 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1979 g_return_if_fail (text != NULL); | |
3922 | 1980 c = text; |
6982 | 1981 len = strlen(text); |
3922 | 1982 ws = g_malloc(len + 1); |
1983 ws[0] = 0; | |
1428 | 1984 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1985 while (pos < len) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1986 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1987 c++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1988 pos++; |
8061 | 1989 ws[wpos] = '\0'; |
1990 switch (type) | |
3922 | 1991 { |
1992 case 1: /* B */ | |
1993 case 2: /* BOLD */ | |
5101 | 1994 case 54: /* STRONG */ |
8677 | 1995 |
1996 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
1997 | |
1998 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD)) | |
8061 | 1999 gtk_imhtml_toggle_bold(imhtml); |
3922 | 2000 bold++; |
8061 | 2001 ws[0] = '\0'; wpos = 0; |
3922 | 2002 break; |
2003 case 3: /* /B */ | |
2004 case 4: /* /BOLD */ | |
5101 | 2005 case 55: /* /STRONG */ |
8677 | 2006 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2007 ws[0] = '\0'; wpos = 0; |
2008 | |
3922 | 2009 if (bold) |
2010 bold--; | |
8677 | 2011 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD) && !imhtml->wbfo) |
8061 | 2012 gtk_imhtml_toggle_bold(imhtml); |
3922 | 2013 break; |
2014 case 5: /* I */ | |
2015 case 6: /* ITALIC */ | |
5101 | 2016 case 52: /* EM */ |
8677 | 2017 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2018 ws[0] = '\0'; wpos = 0; |
8677 | 2019 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC)) |
8061 | 2020 gtk_imhtml_toggle_italic(imhtml); |
3922 | 2021 italics++; |
2022 break; | |
2023 case 7: /* /I */ | |
2024 case 8: /* /ITALIC */ | |
5101 | 2025 case 53: /* /EM */ |
8677 | 2026 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2027 ws[0] = '\0'; wpos = 0; |
3922 | 2028 if (italics) |
2029 italics--; | |
8677 | 2030 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC) && !imhtml->wbfo) |
8061 | 2031 gtk_imhtml_toggle_italic(imhtml); |
3922 | 2032 break; |
2033 case 9: /* U */ | |
2034 case 10: /* UNDERLINE */ | |
8677 | 2035 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2036 ws[0] = '\0'; wpos = 0; |
8677 | 2037 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
8061 | 2038 gtk_imhtml_toggle_underline(imhtml); |
3922 | 2039 underline++; |
2040 break; | |
2041 case 11: /* /U */ | |
2042 case 12: /* /UNDERLINE */ | |
8677 | 2043 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2044 ws[0] = '\0'; wpos = 0; |
3922 | 2045 if (underline) |
2046 underline--; | |
8677 | 2047 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE) && !imhtml->wbfo) |
8061 | 2048 gtk_imhtml_toggle_underline(imhtml); |
3922 | 2049 break; |
2050 case 13: /* S */ | |
2051 case 14: /* STRIKE */ | |
8677 | 2052 /* FIXME: reimplement this */ |
3922 | 2053 strike++; |
2054 break; | |
2055 case 15: /* /S */ | |
2056 case 16: /* /STRIKE */ | |
8677 | 2057 /* FIXME: reimplement this */ |
3922 | 2058 if (strike) |
2059 strike--; | |
2060 break; | |
2061 case 17: /* SUB */ | |
8677 | 2062 /* FIXME: reimpliment this */ |
3922 | 2063 sub++; |
2064 break; | |
2065 case 18: /* /SUB */ | |
8677 | 2066 /* FIXME: reimpliment this */ |
3922 | 2067 if (sub) |
2068 sub--; | |
2069 break; | |
2070 case 19: /* SUP */ | |
8677 | 2071 /* FIXME: reimplement this */ |
3922 | 2072 sup++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2073 break; |
3922 | 2074 case 20: /* /SUP */ |
8677 | 2075 /* FIXME: reimplement this */ |
3922 | 2076 if (sup) |
2077 sup--; | |
2078 break; | |
2079 case 21: /* PRE */ | |
8677 | 2080 /* FIXME: reimplement this */ |
3922 | 2081 pre++; |
2082 break; | |
2083 case 22: /* /PRE */ | |
8677 | 2084 /* FIXME: reimplement this */ |
3922 | 2085 if (pre) |
2086 pre--; | |
2087 break; | |
2088 case 23: /* TITLE */ | |
8677 | 2089 /* FIXME: what was this supposed to do anyway? */ |
3922 | 2090 title++; |
2091 break; | |
2092 case 24: /* /TITLE */ | |
8677 | 2093 /* FIXME: make this undo whatever 23 was supposed to do */ |
3922 | 2094 if (title) { |
2095 if (options & GTK_IMHTML_NO_TITLE) { | |
2096 wpos = 0; | |
2097 ws [wpos] = '\0'; | |
2098 } | |
2099 title--; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2100 } |
3922 | 2101 break; |
2102 case 25: /* BR */ | |
5174 | 2103 case 58: /* BR/ */ |
8061 | 2104 case 61: /* BR (opt) */ |
3922 | 2105 ws[wpos] = '\n'; |
2106 wpos++; | |
6982 | 2107 break; |
3922 | 2108 case 26: /* HR */ |
2109 case 42: /* HR (opt) */ | |
8726 | 2110 { |
2111 int minus; | |
2112 | |
3922 | 2113 ws[wpos++] = '\n'; |
8677 | 2114 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2115 | |
5967 | 2116 scalable = gtk_imhtml_hr_new(); |
8061 | 2117 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
8677 | 2118 scalable->add_to(scalable, imhtml, iter); |
8726 | 2119 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + |
2120 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
2121 scalable->scale(scalable, rect.width - minus, rect.height); | |
8061 | 2122 imhtml->scalables = g_list_append(imhtml->scalables, scalable); |
2123 ws[0] = '\0'; wpos = 0; | |
7942 | 2124 ws[wpos++] = '\n'; |
8061 | 2125 |
3922 | 2126 break; |
8726 | 2127 } |
3922 | 2128 case 27: /* /FONT */ |
8677 | 2129 if (fonts && !imhtml->wbfo) { |
5967 | 2130 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 2131 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2132 ws[0] = '\0'; wpos = 0; |
8177 | 2133 /* NEW_BIT (NEW_TEXT_BIT); */ |
8677 | 2134 |
8698 | 2135 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) { |
8061 | 2136 gtk_imhtml_toggle_fontface(imhtml, NULL); |
3922 | 2137 g_free (font->face); |
8061 | 2138 } |
8698 | 2139 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
8061 | 2140 gtk_imhtml_toggle_forecolor(imhtml, NULL); |
3922 | 2141 g_free (font->fore); |
8061 | 2142 } |
8698 | 2143 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
8061 | 2144 gtk_imhtml_toggle_backcolor(imhtml, NULL); |
3922 | 2145 g_free (font->back); |
8061 | 2146 } |
4032 | 2147 if (font->sml) |
2148 g_free (font->sml); | |
8309 | 2149 |
8698 | 2150 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 2151 gtk_imhtml_font_set_size(imhtml, 3); |
2152 | |
9245 | 2153 g_free(font); |
2154 | |
8309 | 2155 fonts = fonts->next; |
2156 if (fonts) { | |
2157 GtkIMHtmlFontDetail *font = fonts->data; | |
8677 | 2158 |
8698 | 2159 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8309 | 2160 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8698 | 2161 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8309 | 2162 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8698 | 2163 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
8309 | 2164 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8698 | 2165 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 2166 gtk_imhtml_font_set_size(imhtml, font->size); |
2167 } | |
3922 | 2168 } |
8309 | 2169 break; |
3922 | 2170 case 28: /* /A */ |
8677 | 2171 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2172 gtk_imhtml_toggle_link(imhtml, NULL); | |
2173 ws[0] = '\0'; wpos = 0; | |
8061 | 2174 break; |
8118 | 2175 |
3922 | 2176 case 29: /* P */ |
2177 case 30: /* /P */ | |
2178 case 31: /* H3 */ | |
2179 case 32: /* /H3 */ | |
2180 case 33: /* HTML */ | |
2181 case 34: /* /HTML */ | |
2182 case 35: /* BODY */ | |
2183 case 36: /* /BODY */ | |
2184 case 37: /* FONT */ | |
2185 case 38: /* HEAD */ | |
2186 case 39: /* /HEAD */ | |
6982 | 2187 case 40: /* BINARY */ |
2188 case 41: /* /BINARY */ | |
3922 | 2189 break; |
2190 case 43: /* FONT (opt) */ | |
2191 { | |
4032 | 2192 gchar *color, *back, *face, *size, *sml; |
5967 | 2193 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
3922 | 2194 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
2195 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
2196 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
2197 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
4032 | 2198 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
2199 if (!(color || back || face || size || sml)) | |
3922 | 2200 break; |
8061 | 2201 |
8677 | 2202 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2203 ws[0] = '\0'; wpos = 0; |
2204 | |
5967 | 2205 font = g_new0 (GtkIMHtmlFontDetail, 1); |
3922 | 2206 if (fonts) |
2207 oldfont = fonts->data; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2208 |
8677 | 2209 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
3922 | 2210 font->fore = color; |
8061 | 2211 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8677 | 2212 } |
8309 | 2213 //else if (oldfont && oldfont->fore) |
2214 // font->fore = g_strdup(oldfont->fore); | |
8677 | 2215 |
2216 if (back && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { | |
3922 | 2217 font->back = back; |
8061 | 2218 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8309 | 2219 } |
2220 //else if (oldfont && oldfont->back) | |
2221 // font->back = g_strdup(oldfont->back); | |
8677 | 2222 |
2223 if (face && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) { | |
3922 | 2224 font->face = face; |
8061 | 2225 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8309 | 2226 } |
2227 //else if (oldfont && oldfont->face) | |
2228 // font->face = g_strdup(oldfont->face); | |
4032 | 2229 |
2230 if (sml) | |
2231 font->sml = sml; | |
2232 else if (oldfont && oldfont->sml) | |
2233 font->sml = g_strdup(oldfont->sml); | |
2234 | |
8677 | 2235 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) { |
3922 | 2236 if (*size == '+') { |
2237 sscanf (size + 1, "%hd", &font->size); | |
2238 font->size += 3; | |
2239 } else if (*size == '-') { | |
2240 sscanf (size + 1, "%hd", &font->size); | |
2241 font->size = MAX (0, 3 - font->size); | |
2242 } else if (isdigit (*size)) { | |
2243 sscanf (size, "%hd", &font->size); | |
8061 | 2244 } |
6042 | 2245 if (font->size > 100) |
2246 font->size = 100; | |
3922 | 2247 } else if (oldfont) |
2248 font->size = oldfont->size; | |
8309 | 2249 else |
2250 font->size = 3; | |
8698 | 2251 if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
2252 gtk_imhtml_font_set_size(imhtml, font->size); | |
3922 | 2253 g_free(size); |
2254 fonts = g_slist_prepend (fonts, font); | |
2255 } | |
2256 break; | |
2257 case 44: /* BODY (opt) */ | |
2258 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
2259 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
8677 | 2260 if (bgcolor && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
2261 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2262 ws[0] = '\0'; wpos = 0; |
8177 | 2263 /* NEW_BIT(NEW_TEXT_BIT); */ |
3922 | 2264 if (bg) |
2265 g_free(bg); | |
2266 bg = bgcolor; | |
8061 | 2267 gtk_imhtml_toggle_backcolor(imhtml, bg); |
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
2268 } |
1428 | 2269 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2270 break; |
3922 | 2271 case 45: /* A (opt) */ |
2272 { | |
2273 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
8677 | 2274 if (href && (imhtml->format_functions & GTK_IMHTML_LINK)) { |
2275 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2276 ws[0] = '\0'; wpos = 0; |
8677 | 2277 gtk_imhtml_toggle_link(imhtml, href); |
3922 | 2278 } |
2993 | 2279 } |
3922 | 2280 break; |
4895 | 2281 case 46: /* IMG (opt) */ |
6982 | 2282 case 59: /* IMG */ |
4895 | 2283 { |
8962 | 2284 const char *id; |
2285 | |
2286 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
2287 ws[0] = '\0'; wpos = 0; | |
4895 | 2288 |
8677 | 2289 if (!(imhtml->format_functions & GTK_IMHTML_IMAGE)) |
2290 break; | |
2291 | |
8962 | 2292 id = gtk_imhtml_get_html_opt(tag, "ID="); |
9186 | 2293 if (!id) |
2294 break; | |
8962 | 2295 gtk_imhtml_insert_image_at_iter(imhtml, atoi(id), iter); |
2296 break; | |
4895 | 2297 } |
3922 | 2298 case 47: /* P (opt) */ |
2299 case 48: /* H3 (opt) */ | |
5093 | 2300 case 49: /* HTML (opt) */ |
5101 | 2301 case 50: /* CITE */ |
2302 case 51: /* /CITE */ | |
8026 | 2303 case 56: /* SPAN (opt) */ |
8118 | 2304 /* Inline CSS Support - Douglas Thrift |
2305 * | |
2306 * color | |
8686 | 2307 * background |
8118 | 2308 * font-family |
2309 * font-size | |
8686 | 2310 * text-decoration: underline |
8118 | 2311 */ |
2312 { | |
8686 | 2313 gchar *style, *color, *background, *family, *size; |
2314 gchar *textdec; | |
8118 | 2315 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
2316 style = gtk_imhtml_get_html_opt (tag, "style="); | |
2317 | |
2318 if (!style) break; | |
2319 | |
2320 color = gtk_imhtml_get_css_opt (style, "color: "); | |
8686 | 2321 background = gtk_imhtml_get_css_opt (style, "background: "); |
8118 | 2322 family = gtk_imhtml_get_css_opt (style, |
2323 "font-family: "); | |
2324 size = gtk_imhtml_get_css_opt (style, "font-size: "); | |
8686 | 2325 textdec = gtk_imhtml_get_css_opt (style, "text-decoration: "); |
2326 | |
2327 if (!(color || family || size || background || textdec)) { | |
8120 | 2328 g_free(style); |
2329 break; | |
2330 } | |
8118 | 2331 |
8677 | 2332 |
2333 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8118 | 2334 ws[0] = '\0'; wpos = 0; |
8177 | 2335 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2336 |
2337 font = g_new0 (GtkIMHtmlFontDetail, 1); | |
2338 if (fonts) | |
2339 oldfont = fonts->data; | |
2340 | |
8677 | 2341 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8686 | 2342 { |
8118 | 2343 font->fore = color; |
8686 | 2344 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
2345 } | |
8118 | 2346 else if (oldfont && oldfont->fore) |
2347 font->fore = g_strdup(oldfont->fore); | |
2348 | |
8686 | 2349 if (background && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
2350 { | |
2351 font->back = background; | |
2352 gtk_imhtml_toggle_backcolor(imhtml, font->back); | |
2353 } | |
2354 else if (oldfont && oldfont->back) | |
8118 | 2355 font->back = g_strdup(oldfont->back); |
2356 | |
8677 | 2357 if (family && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8686 | 2358 { |
8118 | 2359 font->face = family; |
8686 | 2360 gtk_imhtml_toggle_fontface(imhtml, font->face); |
2361 } | |
8118 | 2362 else if (oldfont && oldfont->face) |
2363 font->face = g_strdup(oldfont->face); | |
2364 if (font->face && (atoi(font->face) > 100)) { | |
8677 | 2365 /* WTF is this? */ |
8118 | 2366 g_free(font->face); |
2367 font->face = g_strdup("100"); | |
2368 } | |
2369 | |
2370 if (oldfont && oldfont->sml) | |
2371 font->sml = g_strdup(oldfont->sml); | |
2372 | |
8677 | 2373 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_SHRINK|GTK_IMHTML_GROW))) { |
8686 | 2374 if (g_ascii_strcasecmp(size, "xx-small") == 0) |
2375 font->size = 1; | |
2376 else if (g_ascii_strcasecmp(size, "smaller") == 0 | |
2377 || g_ascii_strcasecmp(size, "x-small") == 0) | |
8118 | 2378 font->size = 2; |
8686 | 2379 else if (g_ascii_strcasecmp(size, "larger") == 0 |
2380 || g_ascii_strcasecmp(size, "medium") == 0) | |
8118 | 2381 font->size = 4; |
8686 | 2382 else if (g_ascii_strcasecmp(size, "large") == 0) |
2383 font->size = 5; | |
2384 else if (g_ascii_strcasecmp(size, "x-large") == 0) | |
2385 font->size = 6; | |
2386 else if (g_ascii_strcasecmp(size, "xx-large") == 0) | |
2387 font->size = 7; | |
8118 | 2388 else |
2389 font->size = 3; | |
8686 | 2390 gtk_imhtml_font_set_size(imhtml, font->size); |
2391 } | |
2392 else if (oldfont) | |
2393 { | |
2394 font->size = oldfont->size; | |
2395 } | |
2396 | |
2397 if (oldfont) | |
2398 { | |
2399 font->underline = oldfont->underline; | |
2400 } | |
2401 if (textdec && font->underline != 1 | |
9025 | 2402 && g_ascii_strcasecmp(textdec, "underline") == 0 |
8686 | 2403 && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
2404 { | |
2405 gtk_imhtml_toggle_underline(imhtml); | |
2406 font->underline = 1; | |
2407 } | |
8118 | 2408 |
2409 g_free(style); | |
2410 g_free(size); | |
2411 fonts = g_slist_prepend (fonts, font); | |
2412 } | |
2413 break; | |
5104 | 2414 case 57: /* /SPAN */ |
8118 | 2415 /* Inline CSS Support - Douglas Thrift */ |
8677 | 2416 if (fonts && !imhtml->wbfo) { |
8686 | 2417 GtkIMHtmlFontDetail *oldfont = NULL; |
8118 | 2418 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 2419 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8118 | 2420 ws[0] = '\0'; wpos = 0; |
8177 | 2421 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2422 fonts = g_slist_remove (fonts, font); |
8692 | 2423 if (fonts) |
2424 oldfont = fonts->data; | |
2425 | |
2426 if (!oldfont) { | |
2427 gtk_imhtml_font_set_size(imhtml, 3); | |
2428 if (font->underline) | |
2429 gtk_imhtml_toggle_underline(imhtml); | |
2430 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
2431 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
2432 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
8686 | 2433 } |
8692 | 2434 else |
8686 | 2435 { |
8692 | 2436 |
2437 if (font->size != oldfont->size) | |
2438 gtk_imhtml_font_set_size(imhtml, oldfont->size); | |
2439 | |
2440 if (font->underline != oldfont->underline) | |
2441 gtk_imhtml_toggle_underline(imhtml); | |
2442 | |
9286 | 2443 if (font->face && (!oldfont->face || strcmp(font->face, oldfont->face) != 0)) |
8692 | 2444 gtk_imhtml_toggle_fontface(imhtml, oldfont->face); |
2445 | |
9286 | 2446 if (font->fore && (!oldfont->fore || strcmp(font->fore, oldfont->fore) != 0)) |
8692 | 2447 gtk_imhtml_toggle_forecolor(imhtml, oldfont->fore); |
2448 | |
9286 | 2449 if (font->back && (!oldfont->back || strcmp(font->back, oldfont->back) != 0)) |
8692 | 2450 gtk_imhtml_toggle_backcolor(imhtml, oldfont->back); |
8686 | 2451 } |
8692 | 2452 |
2453 g_free (font->face); | |
2454 g_free (font->fore); | |
2455 g_free (font->back); | |
2456 g_free (font->sml); | |
2457 | |
8118 | 2458 g_free (font); |
2459 } | |
2460 break; | |
8026 | 2461 case 60: /* SPAN */ |
2993 | 2462 break; |
8061 | 2463 case 62: /* comment */ |
8177 | 2464 /* NEW_BIT (NEW_TEXT_BIT); */ |
8317 | 2465 ws[wpos] = '\0'; |
8677 | 2466 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2467 | |
6124 | 2468 if (imhtml->show_comments) |
2469 wpos = g_snprintf (ws, len, "%s", tag); | |
8177 | 2470 /* NEW_BIT (NEW_COMMENT_BIT); */ |
3922 | 2471 break; |
2472 default: | |
6882 | 2473 break; |
2993 | 2474 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2475 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2476 pos += tlen; |
4138 | 2477 if(tag) |
2478 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
9029 | 2479 } else if (gtk_imhtml_is_smiley(imhtml, fonts, c, &smilelen)) { |
8473 | 2480 GtkIMHtmlFontDetail *fd; |
2481 | |
2482 gchar *sml = NULL; | |
2483 if (fonts) { | |
2484 fd = fonts->data; | |
2485 sml = fd->sml; | |
2486 } | |
9029 | 2487 if (!sml) |
2488 sml = imhtml->protocol_name; | |
2489 | |
8677 | 2490 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8505 | 2491 wpos = g_snprintf (ws, smilelen + 1, "%s", c); |
8473 | 2492 |
8677 | 2493 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, ws, iter); |
8473 | 2494 |
8505 | 2495 c += smilelen; |
2496 pos += smilelen; | |
8473 | 2497 wpos = 0; |
2498 ws[0] = 0; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2499 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
7280 | 2500 while(*amp) { |
2501 ws [wpos++] = *amp++; | |
2502 } | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2503 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2504 pos += tlen; |
1428 | 2505 } else if (*c == '\n') { |
2506 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
3922 | 2507 ws[wpos] = '\n'; |
2508 wpos++; | |
8677 | 2509 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2510 ws[0] = '\0'; |
2511 wpos = 0; | |
8177 | 2512 /* NEW_BIT (NEW_TEXT_BIT); */ |
1428 | 2513 } |
2514 c++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2515 pos++; |
8334 | 2516 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){ |
2517 while(len_protocol--){ | |
8677 | 2518 /* Skip the next len_protocol characters, but make sure they're |
8334 | 2519 copied into the ws array. |
2520 */ | |
2521 ws [wpos++] = *c++; | |
2522 pos++; | |
2523 } | |
8061 | 2524 } else if (*c) { |
1428 | 2525 ws [wpos++] = *c++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2526 pos++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2527 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2528 break; |
1428 | 2529 } |
2530 } | |
8677 | 2531 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2532 ws[0] = '\0'; wpos = 0; |
2533 | |
8177 | 2534 /* NEW_BIT(NEW_TEXT_BIT); */ |
8061 | 2535 |
4032 | 2536 while (fonts) { |
5967 | 2537 GtkIMHtmlFontDetail *font = fonts->data; |
4032 | 2538 fonts = g_slist_remove (fonts, font); |
2539 if (font->face) | |
2540 g_free (font->face); | |
2541 if (font->fore) | |
2542 g_free (font->fore); | |
2543 if (font->back) | |
2544 g_free (font->back); | |
2545 if (font->sml) | |
2546 g_free (font->sml); | |
2547 g_free (font); | |
2548 } | |
8932 | 2549 |
2550 g_free(ws); | |
2551 if (bg) | |
4630 | 2552 g_free(bg); |
8677 | 2553 |
2554 if (!imhtml->wbfo) | |
8698 | 2555 gtk_imhtml_close_tags(imhtml, iter); |
8506 | 2556 |
2557 object = g_object_ref(G_OBJECT(imhtml)); | |
2558 g_signal_emit(object, signals[UPDATE_FORMAT], 0); | |
2559 g_object_unref(object); | |
2560 | |
3922 | 2561 } |
2562 | |
4892 | 2563 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
2564 { | |
4288 | 2565 g_hash_table_destroy(imhtml->smiley_data); |
2566 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
4892 | 2567 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 2568 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4288 | 2569 imhtml->default_smilies = gtk_smiley_tree_new(); |
2570 } | |
8481 | 2571 |
3922 | 2572 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, |
4253 | 2573 gboolean show) |
2574 { | |
6124 | 2575 imhtml->show_comments = show; |
4253 | 2576 } |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2577 |
8456 | 2578 void gtk_imhtml_html_shortcuts (GtkIMHtml *imhtml, |
2579 gboolean allow) | |
2580 { | |
2581 imhtml->html_shortcuts = allow; | |
2582 } | |
2583 | |
2584 void gtk_imhtml_smiley_shortcuts (GtkIMHtml *imhtml, | |
2585 gboolean allow) | |
2586 { | |
2587 imhtml->smiley_shortcuts = allow; | |
2588 } | |
2589 | |
8962 | 2590 void |
9029 | 2591 gtk_imhtml_set_protocol_name(GtkIMHtml *imhtml, const gchar *protocol_name) { |
2592 if (imhtml->protocol_name) | |
2593 g_free(imhtml->protocol_name); | |
2594 imhtml->protocol_name = protocol_name ? g_strdup(protocol_name) : NULL; | |
8456 | 2595 } |
2596 | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2597 void |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2598 gtk_imhtml_clear (GtkIMHtml *imhtml) |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2599 { |
7991 | 2600 GList *del; |
3922 | 2601 GtkTextIter start, end; |
8427 | 2602 GObject *object = g_object_ref(G_OBJECT(imhtml)); |
7991 | 2603 |
3922 | 2604 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2605 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2606 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
7991 | 2607 |
2608 for(del = imhtml->scalables; del; del = del->next) { | |
2609 GtkIMHtmlScalable *scale = del->data; | |
2610 scale->free(scale); | |
2611 } | |
2612 g_list_free(imhtml->scalables); | |
2613 imhtml->scalables = NULL; | |
8061 | 2614 |
8719 | 2615 gtk_imhtml_close_tags(imhtml, &start); |
8481 | 2616 |
8427 | 2617 g_signal_emit(object, signals[CLEAR_FORMAT], 0); |
2618 g_object_unref(object); | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2619 } |
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
2620 |
4046 | 2621 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
2622 { | |
5282 | 2623 GdkRectangle rect; |
2624 GtkTextIter iter; | |
4046 | 2625 |
5282 | 2626 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
2627 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2628 rect.y - rect.height); | |
2629 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
8061 | 2630 |
4046 | 2631 } |
5282 | 2632 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
2633 { | |
2634 GdkRectangle rect; | |
2635 GtkTextIter iter; | |
2636 | |
2637 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
2638 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2639 rect.y + rect.height); | |
2640 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
2641 } | |
4735 | 2642 |
5967 | 2643 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
8962 | 2644 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id) |
4735 | 2645 { |
5967 | 2646 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
5012 | 2647 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
4895 | 2648 |
5967 | 2649 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
2650 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
2651 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
5046 | 2652 |
2653 im_image->pixbuf = img; | |
5012 | 2654 im_image->image = image; |
4895 | 2655 im_image->width = gdk_pixbuf_get_width(img); |
2656 im_image->height = gdk_pixbuf_get_height(img); | |
2657 im_image->mark = NULL; | |
6982 | 2658 im_image->filename = filename ? g_strdup(filename) : NULL; |
8962 | 2659 im_image->id = id; |
4895 | 2660 |
5046 | 2661 g_object_ref(img); |
4895 | 2662 return GTK_IMHTML_SCALABLE(im_image); |
2663 } | |
2664 | |
5967 | 2665 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
4895 | 2666 { |
5967 | 2667 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
4895 | 2668 |
2669 if(image->width > width || image->height > height){ | |
2670 GdkPixbuf *new_image = NULL; | |
2671 float factor; | |
2672 int new_width = image->width, new_height = image->height; | |
2673 | |
8588 | 2674 if(image->width > (width - 2)){ |
4895 | 2675 factor = (float)(width)/image->width; |
2676 new_width = width; | |
2677 new_height = image->height * factor; | |
2678 } | |
8588 | 2679 if(new_height >= (height - 2)){ |
4895 | 2680 factor = (float)(height)/new_height; |
2681 new_height = height; | |
2682 new_width = new_width * factor; | |
2683 } | |
2684 | |
5046 | 2685 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
5012 | 2686 gtk_image_set_from_pixbuf(image->image, new_image); |
4895 | 2687 g_object_unref(G_OBJECT(new_image)); |
2688 } | |
2689 } | |
2690 | |
5012 | 2691 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel) |
2692 { | |
2693 const gchar *filename = gtk_file_selection_get_filename(sel); | |
5967 | 2694 gchar *dirname; |
2695 GtkIMHtmlImage *image = g_object_get_data(G_OBJECT(sel), "GtkIMHtmlImage"); | |
5012 | 2696 gchar *type = NULL; |
5019 | 2697 GError *error = NULL; |
5015 | 2698 #if GTK_CHECK_VERSION(2,2,0) |
5012 | 2699 GSList *formats = gdk_pixbuf_get_formats(); |
6162 | 2700 #else |
2701 char *basename = g_path_get_basename(filename); | |
2702 char *ext = strrchr(basename, '.'); | |
5959 | 2703 #endif |
5012 | 2704 |
5967 | 2705 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { |
2706 /* append a / if needed */ | |
2707 if (filename[strlen(filename) - 1] != '/') { | |
2708 dirname = g_strconcat(filename, "/", NULL); | |
2709 } else { | |
2710 dirname = g_strdup(filename); | |
2711 } | |
2712 gtk_file_selection_set_filename(sel, dirname); | |
2713 g_free(dirname); | |
5959 | 2714 return; |
5967 | 2715 } |
5959 | 2716 |
2717 #if GTK_CHECK_VERSION(2,2,0) | |
5012 | 2718 while(formats){ |
2719 GdkPixbufFormat *format = formats->data; | |
2720 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
2721 gpointer p = extensions; | |
2722 | |
2723 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
2724 gchar *fmt_ext = extensions[0]; | |
2725 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
2726 | |
2727 if(!strcmp(fmt_ext, file_ext)){ | |
2728 type = gdk_pixbuf_format_get_name(format); | |
2729 break; | |
2730 } | |
2731 | |
2732 extensions++; | |
2733 } | |
2734 | |
2735 g_strfreev(p); | |
2736 | |
2737 if(type) | |
2738 break; | |
2739 | |
2740 formats = formats->next; | |
2741 } | |
2742 | |
5020 | 2743 g_slist_free(formats); |
2744 #else | |
2745 /* this is really ugly code, but I think it will work */ | |
2746 if(ext) { | |
2747 ext++; | |
2748 if(!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) | |
2749 type = g_strdup("jpeg"); | |
2750 else if(!g_ascii_strcasecmp(ext, "png")) | |
2751 type = g_strdup("png"); | |
2752 } | |
2753 | |
2754 g_free(basename); | |
2755 #endif | |
2756 | |
5012 | 2757 /* If I can't find a valid type, I will just tell the user about it and then assume |
2758 it's a png */ | |
2759 if(!type){ | |
2760 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
5967 | 2761 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
5012 | 2762 type = g_strdup("png"); |
2763 } | |
2764 | |
5046 | 2765 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
5012 | 2766 |
2767 if(error){ | |
2768 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
2769 _("Error saving image: %s"), error->message); | |
2770 g_error_free(error); | |
2771 } | |
2772 | |
2773 g_free(type); | |
2774 } | |
2775 | |
5967 | 2776 static void gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) |
5012 | 2777 { |
5967 | 2778 GtkWidget *sel = gtk_file_selection_new(_("Save Image")); |
5012 | 2779 |
6982 | 2780 if (image->filename) |
2781 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename); | |
5967 | 2782 g_object_set_data(G_OBJECT(sel), "GtkIMHtmlImage", image); |
5012 | 2783 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", |
2784 G_CALLBACK(write_img_to_file), sel); | |
2785 | |
2786 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", | |
2787 G_CALLBACK(gtk_widget_destroy), sel); | |
2788 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked", | |
8061 | 2789 G_CALLBACK(gtk_widget_destroy), sel); |
5012 | 2790 |
2791 gtk_widget_show(sel); | |
2792 } | |
2793 | |
5967 | 2794 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
5012 | 2795 { |
2796 GdkEventButton *event_button = (GdkEventButton *) event; | |
2797 | |
2798 if (event->type == GDK_BUTTON_RELEASE) { | |
2799 if(event_button->button == 3) { | |
2800 GtkWidget *img, *item, *menu; | |
2801 gchar *text = g_strdup_printf(_("_Save Image...")); | |
2802 menu = gtk_menu_new(); | |
2803 | |
2804 /* buttons and such */ | |
2805 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
2806 item = gtk_image_menu_item_new_with_mnemonic(text); | |
2807 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
5967 | 2808 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
5012 | 2809 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
2810 | |
2811 gtk_widget_show_all(menu); | |
2812 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
2813 event_button->button, event_button->time); | |
2814 | |
2815 g_free(text); | |
2816 return TRUE; | |
2817 } | |
2818 } | |
2819 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
2820 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
2821 be caught by the regular GtkTextView menu */ | |
2822 else | |
2823 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
2824 | |
2825 } | |
5967 | 2826 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
2827 { | |
2828 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2829 | |
2830 g_object_unref(image->pixbuf); | |
6982 | 2831 if (image->filename) |
2832 g_free(image->filename); | |
5967 | 2833 g_free(scale); |
2834 } | |
2835 | |
2836 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2837 { | |
2838 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2839 GtkWidget *box = gtk_event_box_new(); | |
8962 | 2840 char *tag; |
5967 | 2841 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
2842 | |
2843 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
9229 | 2844 |
2845 if(!gtk_check_version(2, 4, 0)) | |
2846 g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL); | |
5967 | 2847 |
2848 gtk_widget_show(GTK_WIDGET(image->image)); | |
2849 gtk_widget_show(box); | |
2850 | |
8962 | 2851 tag = g_strdup_printf("<IMG ID=\"%d\">", image->id); |
2852 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", tag, g_free); | |
2853 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "[Image]"); | |
2854 | |
5967 | 2855 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); |
2856 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
2857 } | |
2858 | |
2859 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
2860 { | |
2861 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
2862 | |
2863 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
2864 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
2865 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
2866 | |
2867 hr->sep = gtk_hseparator_new(); | |
2868 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
2869 gtk_widget_show(hr->sep); | |
2870 | |
2871 return GTK_IMHTML_SCALABLE(hr); | |
2872 } | |
2873 | |
2874 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
2875 { | |
8588 | 2876 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width - 2, 2); |
5967 | 2877 } |
2878 | |
2879 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2880 { | |
2881 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
2882 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
8698 | 2883 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_htmltext", "<hr>"); |
2884 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "\n---\n"); | |
5967 | 2885 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); |
2886 } | |
2887 | |
2888 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
2889 { | |
2890 g_free(scale); | |
2891 } | |
7295 | 2892 |
2893 gboolean gtk_imhtml_search_find(GtkIMHtml *imhtml, const gchar *text) | |
2894 { | |
2895 GtkTextIter iter, start, end; | |
2896 gboolean new_search = TRUE; | |
2897 | |
2898 g_return_val_if_fail(imhtml != NULL, FALSE); | |
2899 g_return_val_if_fail(text != NULL, FALSE); | |
8061 | 2900 |
7295 | 2901 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) |
2902 new_search = FALSE; | |
8061 | 2903 |
7295 | 2904 if (new_search) { |
2905 gtk_imhtml_search_clear(imhtml); | |
2906 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
2907 } else { | |
2908 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, | |
8061 | 2909 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); |
7295 | 2910 } |
2911 imhtml->search_string = g_strdup(text); | |
2912 | |
7358 | 2913 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, |
2914 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
7295 | 2915 &start, &end, NULL)) { |
2916 | |
2917 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); | |
2918 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); | |
2919 if (new_search) { | |
2920 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); | |
8061 | 2921 do |
7295 | 2922 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); |
8061 | 2923 while (gtk_source_iter_forward_search(&end, imhtml->search_string, |
2924 GTK_SOURCE_SEARCH_VISIBLE_ONLY | | |
7358 | 2925 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, |
7295 | 2926 &start, &end, NULL)); |
2927 } | |
2928 return TRUE; | |
2929 } | |
8061 | 2930 |
2931 gtk_imhtml_search_clear(imhtml); | |
2932 | |
7295 | 2933 return FALSE; |
2934 } | |
2935 | |
2936 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) | |
2937 { | |
2938 GtkTextIter start, end; | |
8061 | 2939 |
7295 | 2940 g_return_if_fail(imhtml != NULL); |
8061 | 2941 |
7295 | 2942 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2943 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2944 | |
2945 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
2946 if (imhtml->search_string) | |
2947 g_free(imhtml->search_string); | |
2948 imhtml->search_string = NULL; | |
2949 } | |
8061 | 2950 |
8677 | 2951 static GtkTextTag *find_font_forecolor_tag(GtkIMHtml *imhtml, gchar *color) |
2952 { | |
2953 gchar str[18]; | |
2954 GtkTextTag *tag; | |
2955 | |
2956 g_snprintf(str, sizeof(str), "FORECOLOR %s", color); | |
2957 | |
2958 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
2959 if (!tag) | |
2960 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", color, NULL); | |
2961 | |
2962 return tag; | |
2963 } | |
2964 | |
2965 static GtkTextTag *find_font_backcolor_tag(GtkIMHtml *imhtml, gchar *color) | |
2966 { | |
2967 gchar str[18]; | |
2968 GtkTextTag *tag; | |
2969 | |
2970 g_snprintf(str, sizeof(str), "BACKCOLOR %s", color); | |
2971 | |
2972 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
2973 if (!tag) | |
2974 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "background", color, NULL); | |
2975 | |
2976 return tag; | |
2977 } | |
2978 | |
2979 static GtkTextTag *find_font_face_tag(GtkIMHtml *imhtml, gchar *face) | |
8061 | 2980 { |
8677 | 2981 gchar str[256]; |
2982 GtkTextTag *tag; | |
2983 | |
2984 g_snprintf(str, sizeof(str), "FONT FACE %s", face); | |
2985 str[255] = '\0'; | |
2986 | |
2987 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
2988 if (!tag) | |
2989 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "family", face, NULL); | |
2990 | |
2991 return tag; | |
2992 } | |
2993 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2994 static void _init_original_fsize(GtkIMHtml *imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2995 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2996 GtkTextAttributes *attr; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2997 attr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2998 imhtml->original_fsize = pango_font_description_get_size(attr->font); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2999 gtk_text_attributes_unref(attr); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3000 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3001 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3002 static void _recalculate_font_sizes(GtkTextTag *tag, gpointer imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3003 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3004 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3005 int size; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3006 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3007 size = strtol(tag->name + 10, NULL, 10); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3008 g_object_set(G_OBJECT(tag), "size", |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3009 (gint) (GTK_IMHTML(imhtml)->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3010 ((double) _point_sizes[size-1] * GTK_IMHTML(imhtml)->zoom)), NULL); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3011 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3012 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3013 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3014 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3015 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3016 void gtk_imhtml_font_zoom(GtkIMHtml *imhtml, double zoom) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3017 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3018 GtkRcStyle *s; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3019 PangoFontDescription *font_desc = pango_font_description_new(); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3020 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3021 imhtml->zoom = zoom; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3022 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3023 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3024 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3025 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3026 gtk_text_tag_table_foreach(gtk_text_buffer_get_tag_table(imhtml->text_buffer), |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3027 _recalculate_font_sizes, imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3028 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3029 pango_font_description_set_size(font_desc, (gint)((double) imhtml->original_fsize * zoom)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3030 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3031 s = gtk_widget_get_modifier_style(GTK_WIDGET(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3032 s->font_desc = font_desc; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3033 gtk_widget_modify_style(GTK_WIDGET(imhtml), s); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3034 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3035 |
8677 | 3036 static GtkTextTag *find_font_size_tag(GtkIMHtml *imhtml, int size) |
3037 { | |
3038 gchar str[24]; | |
3039 GtkTextTag *tag; | |
3040 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3041 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3042 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3043 |
8677 | 3044 g_snprintf(str, sizeof(str), "FONT SIZE %d", size); |
3045 str[23] = '\0'; | |
3046 | |
3047 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3048 if (!tag) { | |
3049 /* For reasons I don't understand, setting "scale" here scaled based on some default | |
3050 * size other than my theme's default size. Our size 4 was actually smaller than | |
3051 * our size 3 for me. So this works around that oddity. | |
3052 */ | |
3053 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "size", | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3054 (gint) (imhtml->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3055 ((double) _point_sizes[size-1] * imhtml->zoom)), NULL); |
8061 | 3056 } |
3057 | |
8677 | 3058 return tag; |
3059 } | |
3060 | |
3061 static void remove_tag_by_prefix(GtkIMHtml *imhtml, const GtkTextIter *i, const GtkTextIter *e, | |
3062 const char *prefix, guint len, gboolean homo) | |
3063 { | |
3064 GSList *tags, *l; | |
3065 GtkTextIter iter; | |
3066 | |
3067 tags = gtk_text_iter_get_tags(i); | |
3068 | |
3069 for (l = tags; l; l = l->next) { | |
3070 GtkTextTag *tag = l->data; | |
3071 | |
3072 if (tag->name && !strncmp(tag->name, prefix, len)) | |
3073 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, i, e); | |
8061 | 3074 } |
3075 | |
8677 | 3076 g_slist_free(tags); |
3077 | |
3078 if (homo) | |
3079 return; | |
3080 | |
3081 iter = *i; | |
3082 | |
3083 while (gtk_text_iter_forward_char(&iter) && !gtk_text_iter_equal(&iter, e)) { | |
3084 if (gtk_text_iter_begins_tag(&iter, NULL)) { | |
3085 tags = gtk_text_iter_get_toggled_tags(&iter, TRUE); | |
3086 | |
3087 for (l = tags; l; l = l->next) { | |
3088 GtkTextTag *tag = l->data; | |
3089 | |
3090 if (tag->name && !strncmp(tag->name, prefix, len)) | |
3091 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, &iter, e); | |
3092 } | |
3093 | |
3094 g_slist_free(tags); | |
3095 } | |
8061 | 3096 } |
8677 | 3097 } |
3098 | |
3099 static void remove_font_size(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3100 { | |
3101 remove_tag_by_prefix(imhtml, i, e, "FONT SIZE ", 10, homo); | |
3102 } | |
3103 | |
3104 static void remove_font_face(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3105 { | |
3106 remove_tag_by_prefix(imhtml, i, e, "FONT FACE ", 10, homo); | |
3107 } | |
3108 | |
3109 static void remove_font_forecolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3110 { | |
3111 remove_tag_by_prefix(imhtml, i, e, "FORECOLOR ", 10, homo); | |
3112 } | |
3113 | |
3114 static void remove_font_backcolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3115 { | |
3116 remove_tag_by_prefix(imhtml, i, e, "BACKCOLOR ", 10, homo); | |
3117 } | |
3118 | |
3119 static void remove_font_link(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3120 { | |
3121 remove_tag_by_prefix(imhtml, i, e, "LINK ", 5, homo); | |
3122 } | |
3123 | |
3124 /* Editable stuff */ | |
3125 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) | |
3126 { | |
3127 imhtml->insert_offset = gtk_text_iter_get_offset(iter); | |
3128 } | |
3129 | |
3130 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *end, gchar *text, gint len, GtkIMHtml *imhtml) | |
3131 { | |
3132 GtkTextIter start; | |
3133 | |
3134 if (!len) | |
3135 return; | |
3136 | |
3137 start = *end; | |
3138 gtk_text_iter_set_offset(&start, imhtml->insert_offset); | |
3139 | |
3140 if (imhtml->edit.bold) | |
3141 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, end); | |
3142 else | |
3143 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, end); | |
3144 | |
3145 if (imhtml->edit.italic) | |
3146 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end); | |
3147 else | |
3148 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end); | |
3149 | |
3150 if (imhtml->edit.underline) | |
3151 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end); | |
3152 else | |
3153 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end); | |
3154 | |
3155 if (imhtml->edit.forecolor) { | |
3156 remove_font_forecolor(imhtml, &start, end, TRUE); | |
3157 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3158 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
3159 &start, end); | |
8061 | 3160 } |
3161 | |
8677 | 3162 if (imhtml->edit.backcolor) { |
3163 remove_font_backcolor(imhtml, &start, end, TRUE); | |
3164 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3165 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), | |
3166 &start, end); | |
3167 } | |
3168 | |
3169 if (imhtml->edit.fontface) { | |
3170 remove_font_face(imhtml, &start, end, TRUE); | |
3171 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3172 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
3173 &start, end); | |
8061 | 3174 } |
8677 | 3175 |
3176 if (imhtml->edit.fontsize) { | |
3177 remove_font_size(imhtml, &start, end, TRUE); | |
3178 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3179 find_font_size_tag(imhtml, imhtml->edit.fontsize), | |
3180 &start, end); | |
3181 } | |
3182 | |
3183 if (imhtml->edit.link) { | |
3184 remove_font_link(imhtml, &start, end, TRUE); | |
3185 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3186 imhtml->edit.link, | |
3187 &start, end); | |
3188 } | |
3189 | |
8061 | 3190 } |
3191 | |
3192 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) | |
3193 { | |
3194 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); | |
8177 | 3195 /* |
3196 * We need a visible caret for accessibility, so mouseless | |
3197 * people can highlight stuff. | |
3198 */ | |
3199 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */ | |
8061 | 3200 imhtml->editable = editable; |
8677 | 3201 imhtml->format_functions = GTK_IMHTML_ALL; |
3202 | |
3203 if (editable) | |
3204 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set", | |
3205 G_CALLBACK(mark_set_cb), imhtml); | |
3206 } | |
3207 | |
3208 void gtk_imhtml_set_whole_buffer_formatting_only(GtkIMHtml *imhtml, gboolean wbfo) | |
3209 { | |
3210 g_return_if_fail(imhtml != NULL); | |
3211 | |
3212 imhtml->wbfo = wbfo; | |
8420 | 3213 } |
3214 | |
3215 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons) | |
3216 { | |
3217 GObject *object = g_object_ref(G_OBJECT(imhtml)); | |
8677 | 3218 imhtml->format_functions = buttons; |
8420 | 3219 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons); |
3220 g_object_unref(object); | |
8061 | 3221 } |
3222 | |
8788 | 3223 GtkIMHtmlButtons gtk_imhtml_get_format_functions(GtkIMHtml *imhtml) |
3224 { | |
3225 return imhtml->format_functions; | |
3226 } | |
8516 | 3227 |
3228 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold, | |
3229 gboolean *italic, gboolean *underline) | |
8481 | 3230 { |
8677 | 3231 if (imhtml->edit.bold) |
3232 (*bold) = TRUE; | |
3233 if (imhtml->edit.italic) | |
3234 (*italic) = TRUE; | |
3235 if (imhtml->edit.underline) | |
3236 (*underline) = TRUE; | |
8481 | 3237 } |
3238 | |
9025 | 3239 char * |
3240 gtk_imhtml_get_current_fontface(GtkIMHtml *imhtml) | |
3241 { | |
3242 if (imhtml->edit.fontface) | |
3243 return g_strdup(imhtml->edit.fontface); | |
3244 else | |
3245 return NULL; | |
3246 } | |
3247 | |
3248 char * | |
3249 gtk_imhtml_get_current_forecolor(GtkIMHtml *imhtml) | |
3250 { | |
3251 if (imhtml->edit.forecolor) | |
3252 return g_strdup(imhtml->edit.forecolor); | |
3253 else | |
3254 return NULL; | |
3255 } | |
3256 | |
3257 char * | |
3258 gtk_imhtml_get_current_backcolor(GtkIMHtml *imhtml) | |
3259 { | |
3260 if (imhtml->edit.backcolor) | |
3261 return g_strdup(imhtml->edit.backcolor); | |
3262 else | |
3263 return NULL; | |
3264 } | |
3265 | |
3266 gint | |
3267 gtk_imhtml_get_current_fontsize(GtkIMHtml *imhtml) | |
3268 { | |
3269 return imhtml->edit.fontsize; | |
3270 } | |
3271 | |
8061 | 3272 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) |
3273 { | |
3274 return imhtml->editable; | |
3275 } | |
3276 | |
8677 | 3277 /* |
3278 * I had this crazy idea about changing the text cursor color to reflex the foreground color | |
3279 * of the text about to be entered. This is the place you'd do it, along with the place where | |
3280 * we actually set a new foreground color. | |
3281 * I may not do this, because people will bitch about Gaim overriding their gtk theme's cursor | |
3282 * colors. | |
3283 * | |
3284 * Just in case I do do this, I asked about what to set the secondary text cursor to. | |
3285 * | |
8719 | 3286 * (12:45:27) ?? ???: secondary_cursor_color = (rgb(background) + rgb(primary_cursor_color) ) / 2 |
3287 * (12:45:55) ?? ???: understand? | |
8677 | 3288 * (12:46:14) Tim: yeah. i didn't know there was an exact formula |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8729
diff
changeset
|
3289 * (12:46:56) ?? ???: u might need to extract separate each color from RGB |
8677 | 3290 */ |
3291 | |
3292 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, | |
3293 GtkIMHtml *imhtml) | |
3294 { | |
3295 GSList *tags, *l; | |
3296 GtkTextIter iter; | |
3297 | |
3298 if (mark != gtk_text_buffer_get_insert(buffer)) | |
3299 return; | |
3300 | |
3301 if (!gtk_text_buffer_get_char_count(buffer)) | |
3302 return; | |
3303 | |
3304 imhtml->edit.bold = imhtml->edit.italic = imhtml->edit.underline = FALSE; | |
3305 if (imhtml->edit.forecolor) | |
3306 g_free(imhtml->edit.forecolor); | |
3307 imhtml->edit.forecolor = NULL; | |
3308 if (imhtml->edit.backcolor) | |
3309 g_free(imhtml->edit.backcolor); | |
3310 imhtml->edit.backcolor = NULL; | |
3311 if (imhtml->edit.fontface) | |
3312 g_free(imhtml->edit.fontface); | |
3313 imhtml->edit.fontface = NULL; | |
3314 imhtml->edit.fontsize = 0; | |
3315 imhtml->edit.link = NULL; | |
3316 | |
3317 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3318 | |
3319 | |
3320 if (gtk_text_iter_is_end(&iter)) | |
3321 tags = gtk_text_iter_get_toggled_tags(&iter, FALSE); | |
3322 else | |
3323 tags = gtk_text_iter_get_tags(&iter); | |
3324 | |
3325 for (l = tags; l != NULL; l = l->next) { | |
3326 GtkTextTag *tag = GTK_TEXT_TAG(l->data); | |
3327 | |
3328 if (tag->name) { | |
3329 if (strcmp(tag->name, "BOLD") == 0) | |
3330 imhtml->edit.bold = TRUE; | |
3331 if (strcmp(tag->name, "ITALICS") == 0) | |
3332 imhtml->edit.italic = TRUE; | |
3333 if (strcmp(tag->name, "UNDERLINE") == 0) | |
3334 imhtml->edit.underline = TRUE; | |
3335 if (strncmp(tag->name, "FORECOLOR ", 10) == 0) | |
3336 imhtml->edit.forecolor = g_strdup(&(tag->name)[10]); | |
3337 if (strncmp(tag->name, "BACKCOLOR ", 10) == 0) | |
3338 imhtml->edit.backcolor = g_strdup(&(tag->name)[10]); | |
3339 if (strncmp(tag->name, "FONT FACE ", 10) == 0) | |
3340 imhtml->edit.fontface = g_strdup(&(tag->name)[10]); | |
3341 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) | |
3342 imhtml->edit.fontsize = strtol(&(tag->name)[10], NULL, 10); | |
8719 | 3343 if ((strncmp(tag->name, "LINK ", 5) == 0) && !gtk_text_iter_is_end(&iter)) |
8677 | 3344 imhtml->edit.link = tag; |
3345 } | |
3346 } | |
3347 | |
3348 g_slist_free(tags); | |
3349 } | |
3350 | |
8061 | 3351 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) |
3352 { | |
8481 | 3353 GObject *object; |
8677 | 3354 GtkTextIter start, end; |
3355 | |
3356 imhtml->edit.bold = !imhtml->edit.bold; | |
3357 | |
3358 if (imhtml->wbfo) { | |
3359 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3360 if (imhtml->edit.bold) | |
3361 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3362 else | |
3363 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3364 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3365 if (imhtml->edit.bold) | |
3366 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3367 else | |
3368 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3369 | |
8061 | 3370 } |
8481 | 3371 object = g_object_ref(G_OBJECT(imhtml)); |
3372 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BOLD); | |
3373 g_object_unref(object); | |
3374 | |
8677 | 3375 return (imhtml->edit.bold != FALSE); |
8061 | 3376 } |
3377 | |
3378 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) | |
3379 { | |
8481 | 3380 GObject *object; |
8677 | 3381 GtkTextIter start, end; |
3382 | |
3383 imhtml->edit.italic = !imhtml->edit.italic; | |
3384 | |
3385 if (imhtml->wbfo) { | |
3386 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3387 if (imhtml->edit.italic) | |
3388 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3389 else | |
3390 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3391 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3392 if (imhtml->edit.italic) | |
3393 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3394 else | |
3395 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
8061 | 3396 } |
8481 | 3397 object = g_object_ref(G_OBJECT(imhtml)); |
3398 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_ITALIC); | |
3399 g_object_unref(object); | |
3400 | |
8677 | 3401 return imhtml->edit.italic != FALSE; |
8061 | 3402 } |
3403 | |
3404 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) | |
3405 { | |
8481 | 3406 GObject *object; |
8677 | 3407 GtkTextIter start, end; |
3408 | |
3409 imhtml->edit.underline = !imhtml->edit.underline; | |
3410 | |
3411 if (imhtml->wbfo) { | |
3412 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3413 if (imhtml->edit.underline) | |
3414 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3415 else | |
3416 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3417 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3418 if (imhtml->edit.underline) | |
3419 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3420 else | |
3421 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
8061 | 3422 } |
8481 | 3423 object = g_object_ref(G_OBJECT(imhtml)); |
3424 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_UNDERLINE); | |
3425 g_object_unref(object); | |
3426 | |
8677 | 3427 return imhtml->edit.underline != FALSE; |
8061 | 3428 } |
3429 | |
3430 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) | |
3431 { | |
9025 | 3432 GObject *object; |
8677 | 3433 GtkTextIter start, end; |
9025 | 3434 GtkIMHtmlButtons b = 0; |
8061 | 3435 |
3436 imhtml->edit.fontsize = size; | |
3437 | |
8677 | 3438 |
3439 if (imhtml->wbfo) { | |
3440 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3441 remove_font_size(imhtml, &start, &end, TRUE); | |
3442 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3443 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3444 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3445 remove_font_size(imhtml, &start, &end, FALSE); | |
3446 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3447 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3448 } |
8677 | 3449 |
9025 | 3450 object = g_object_ref(G_OBJECT(imhtml)); |
3451 b |= GTK_IMHTML_SHRINK; | |
3452 b |= GTK_IMHTML_GROW; | |
3453 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, b); | |
3454 g_object_unref(object); | |
8061 | 3455 } |
3456 | |
3457 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) | |
3458 { | |
9025 | 3459 GObject *object; |
8677 | 3460 GtkTextIter start, end; |
3461 | |
8061 | 3462 if (imhtml->edit.fontsize == 1) |
3463 return; | |
3464 | |
8677 | 3465 if (!imhtml->edit.fontsize) |
3466 imhtml->edit.fontsize = 2; | |
3467 else | |
3468 imhtml->edit.fontsize--; | |
3469 | |
3470 if (imhtml->wbfo) { | |
3471 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3472 remove_font_size(imhtml, &start, &end, TRUE); | |
3473 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3474 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3475 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3476 remove_font_size(imhtml, &start, &end, FALSE); | |
3477 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3478 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3479 } |
9025 | 3480 object = g_object_ref(G_OBJECT(imhtml)); |
3481 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_SHRINK); | |
3482 g_object_unref(object); | |
8061 | 3483 } |
3484 | |
3485 void gtk_imhtml_font_grow(GtkIMHtml *imhtml) | |
3486 { | |
9025 | 3487 GObject *object; |
8677 | 3488 GtkTextIter start, end; |
3489 | |
8061 | 3490 if (imhtml->edit.fontsize == MAX_FONT_SIZE) |
3491 return; | |
3492 | |
8677 | 3493 if (!imhtml->edit.fontsize) |
3494 imhtml->edit.fontsize = 4; | |
3495 else | |
3496 imhtml->edit.fontsize++; | |
3497 | |
3498 if (imhtml->wbfo) { | |
3499 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3500 remove_font_size(imhtml, &start, &end, TRUE); | |
3501 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3502 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3503 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3504 remove_font_size(imhtml, &start, &end, FALSE); | |
3505 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3506 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3507 } |
9025 | 3508 object = g_object_ref(G_OBJECT(imhtml)); |
3509 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_GROW); | |
3510 g_object_unref(object); | |
8061 | 3511 } |
3512 | |
3513 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) | |
3514 { | |
9025 | 3515 GObject *object; |
8677 | 3516 GtkTextIter start, end; |
3517 | |
3518 if (imhtml->edit.forecolor != NULL) | |
3519 g_free(imhtml->edit.forecolor); | |
3520 | |
9025 | 3521 if (color && strcmp(color, "") != 0) { |
8677 | 3522 imhtml->edit.forecolor = g_strdup(color); |
3523 if (imhtml->wbfo) { | |
3524 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3525 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
3526 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3527 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), &start, &end); | |
3528 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3529 remove_font_forecolor(imhtml, &start, &end, FALSE); | |
3530 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3531 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
3532 &start, &end); | |
3533 } | |
8061 | 3534 } else { |
3535 imhtml->edit.forecolor = NULL; | |
9025 | 3536 if (imhtml->wbfo) { |
3537 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3538 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
3539 } | |
8061 | 3540 } |
3541 | |
9025 | 3542 object = g_object_ref(G_OBJECT(imhtml)); |
3543 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_FORECOLOR); | |
3544 g_object_unref(object); | |
3545 | |
8061 | 3546 return imhtml->edit.forecolor != NULL; |
3547 } | |
3548 | |
3549 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) | |
3550 { | |
9025 | 3551 GObject *object; |
8677 | 3552 GtkTextIter start, end; |
3553 | |
3554 if (imhtml->edit.backcolor != NULL) | |
3555 g_free(imhtml->edit.backcolor); | |
3556 | |
9025 | 3557 if (color && strcmp(color, "") != 0) { |
8677 | 3558 imhtml->edit.backcolor = g_strdup(color); |
3559 | |
3560 if (imhtml->wbfo) { | |
3561 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3562 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
3563 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3564 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), &start, &end); | |
3565 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3566 remove_font_backcolor(imhtml, &start, &end, FALSE); | |
3567 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3568 find_font_backcolor_tag(imhtml, | |
3569 imhtml->edit.backcolor), &start, &end); | |
3570 } | |
8061 | 3571 } else { |
3572 imhtml->edit.backcolor = NULL; | |
9025 | 3573 if (imhtml->wbfo) { |
3574 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3575 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
3576 } | |
8061 | 3577 } |
8677 | 3578 |
9025 | 3579 object = g_object_ref(G_OBJECT(imhtml)); |
3580 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BACKCOLOR); | |
3581 g_object_unref(object); | |
3582 | |
8061 | 3583 return imhtml->edit.backcolor != NULL; |
3584 } | |
3585 | |
3586 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) | |
3587 { | |
9025 | 3588 GObject *object; |
8677 | 3589 GtkTextIter start, end; |
3590 | |
3591 if (imhtml->edit.fontface != NULL) | |
3592 g_free(imhtml->edit.fontface); | |
3593 | |
9025 | 3594 if (face && strcmp(face, "") != 0) { |
8677 | 3595 imhtml->edit.fontface = g_strdup(face); |
3596 | |
3597 if (imhtml->wbfo) { | |
3598 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3599 remove_font_face(imhtml, &start, &end, TRUE); | |
3600 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3601 find_font_face_tag(imhtml, imhtml->edit.fontface), &start, &end); | |
3602 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3603 remove_font_face(imhtml, &start, &end, FALSE); | |
3604 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3605 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
3606 &start, &end); | |
3607 } | |
8061 | 3608 } else { |
3609 imhtml->edit.fontface = NULL; | |
9025 | 3610 if (imhtml->wbfo) { |
3611 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3612 remove_font_face(imhtml, &start, &end, TRUE); | |
3613 } | |
8061 | 3614 } |
8677 | 3615 |
9025 | 3616 object = g_object_ref(G_OBJECT(imhtml)); |
3617 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_FACE); | |
3618 g_object_unref(object); | |
3619 | |
8061 | 3620 return imhtml->edit.fontface != NULL; |
3621 } | |
3622 | |
8677 | 3623 void gtk_imhtml_toggle_link(GtkIMHtml *imhtml, const char *url) |
8061 | 3624 { |
9025 | 3625 GObject *object; |
8677 | 3626 GtkTextIter start, end; |
3627 GtkTextTag *linktag; | |
3628 static guint linkno = 0; | |
3629 gchar str[48]; | |
9007 | 3630 GdkColor *color = NULL; |
8677 | 3631 |
3632 imhtml->edit.link = NULL; | |
3633 | |
3634 | |
3635 | |
3636 if (url) { | |
3637 g_snprintf(str, sizeof(str), "LINK %d", linkno++); | |
3638 str[47] = '\0'; | |
3639 | |
9007 | 3640 gtk_widget_style_get(GTK_WIDGET(imhtml), "hyperlink-color", &color, NULL); |
9008 | 3641 if (color) { |
9007 | 3642 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground-gdk", color, "underline", PANGO_UNDERLINE_SINGLE, NULL); |
9008 | 3643 gdk_color_free(color); |
3644 } else { | |
9007 | 3645 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); |
9008 | 3646 } |
8677 | 3647 g_object_set_data_full(G_OBJECT(linktag), "link_url", g_strdup(url), g_free); |
3648 g_signal_connect(G_OBJECT(linktag), "event", G_CALLBACK(tag_event), NULL); | |
3649 | |
3650 if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3651 remove_font_link(imhtml, &start, &end, FALSE); | |
3652 gtk_text_buffer_apply_tag(imhtml->text_buffer, linktag, &start, &end); | |
3653 } | |
3654 } | |
9025 | 3655 |
3656 object = g_object_ref(G_OBJECT(imhtml)); | |
3657 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_LINK); | |
3658 g_object_unref(object); | |
8677 | 3659 } |
3660 | |
3661 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, GtkTextMark *mark, const char *url, const char *text) | |
3662 { | |
8061 | 3663 GtkTextIter iter; |
8677 | 3664 |
3665 gtk_imhtml_toggle_link(imhtml, url); | |
8061 | 3666 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); |
8677 | 3667 gtk_text_buffer_insert(imhtml->text_buffer, &iter, text, -1); |
3668 gtk_imhtml_toggle_link(imhtml, NULL); | |
8061 | 3669 } |
3670 | |
3671 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley) | |
3672 { | |
8677 | 3673 GtkTextMark *mark; |
8061 | 3674 GtkTextIter iter; |
8677 | 3675 |
3676 mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
3677 | |
3678 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3679 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, smiley, &iter); | |
3680 } | |
3681 | |
3682 void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *smiley, GtkTextIter *iter) | |
3683 { | |
8061 | 3684 GdkPixbuf *pixbuf = NULL; |
3685 GdkPixbufAnimation *annipixbuf = NULL; | |
3686 GtkWidget *icon = NULL; | |
3687 GtkTextChildAnchor *anchor; | |
8505 | 3688 char *unescaped = gaim_unescape_html(smiley); |
8061 | 3689 |
8505 | 3690 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); |
8061 | 3691 if(annipixbuf) { |
3692 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
3693 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
3694 if(pixbuf) | |
3695 icon = gtk_image_new_from_pixbuf(pixbuf); | |
3696 } else { | |
3697 icon = gtk_image_new_from_animation(annipixbuf); | |
3698 } | |
3699 } | |
3700 | |
3701 if (icon) { | |
8890 | 3702 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
3703 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", g_strdup(unescaped), g_free); | |
3704 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free); | |
3705 | |
8061 | 3706 gtk_widget_show(icon); |
3707 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); | |
8890 | 3708 } else { |
3709 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, -1); | |
8061 | 3710 } |
8890 | 3711 |
3712 g_free(unescaped); | |
8061 | 3713 } |
3714 | |
8962 | 3715 void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *iter) |
3716 { | |
3717 GdkPixbuf *pixbuf = NULL; | |
3718 const char *filename = NULL; | |
3719 gpointer image; | |
3720 GdkRectangle rect; | |
3721 GtkIMHtmlScalable *scalable = NULL; | |
3722 int minus; | |
3723 | |
3724 if (!imhtml->funcs || !imhtml->funcs->image_get || | |
3725 !imhtml->funcs->image_get_size || !imhtml->funcs->image_get_data || | |
3726 !imhtml->funcs->image_get_filename || !imhtml->funcs->image_ref || | |
3727 !imhtml->funcs->image_unref) | |
3728 return; | |
3729 | |
3730 image = imhtml->funcs->image_get(id); | |
3731 | |
3732 if (image) { | |
3733 gpointer data; | |
3734 size_t len; | |
3735 | |
3736 data = imhtml->funcs->image_get_data(image); | |
3737 len = imhtml->funcs->image_get_size(image); | |
3738 | |
3739 if (data && len) { | |
3740 GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); | |
3741 gdk_pixbuf_loader_write(loader, data, len, NULL); | |
3742 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); | |
9337 | 3743 if (pixbuf) |
3744 g_object_ref(G_OBJECT(pixbuf)); | |
8962 | 3745 gdk_pixbuf_loader_close(loader, NULL); |
9337 | 3746 g_object_unref(G_OBJECT(loader)); |
8962 | 3747 } |
3748 | |
3749 } | |
3750 | |
3751 if (pixbuf) { | |
3752 filename = imhtml->funcs->image_get_filename(image); | |
3753 imhtml->funcs->image_ref(id); | |
3754 imhtml->im_images = g_slist_prepend(imhtml->im_images, GINT_TO_POINTER(id)); | |
3755 } else { | |
3756 pixbuf = gtk_widget_render_icon(GTK_WIDGET(imhtml), GTK_STOCK_MISSING_IMAGE, | |
3757 GTK_ICON_SIZE_BUTTON, "gtkimhtml-missing-image"); | |
3758 } | |
3759 | |
3760 scalable = gtk_imhtml_image_new(pixbuf, filename, id); | |
3761 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
3762 scalable->add_to(scalable, imhtml, iter); | |
3763 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + | |
3764 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
3765 scalable->scale(scalable, rect.width - minus, rect.height); | |
3766 imhtml->scalables = g_list_append(imhtml->scalables, scalable); | |
3767 | |
3768 g_object_unref(G_OBJECT(pixbuf)); | |
3769 } | |
3770 | |
8677 | 3771 static const gchar *tag_to_html_start(GtkTextTag *tag) |
8061 | 3772 { |
8677 | 3773 const gchar *name; |
3774 static gchar buf[1024]; | |
3775 | |
3776 name = tag->name; | |
3777 g_return_val_if_fail(name != NULL, ""); | |
3778 | |
3779 if (strcmp(name, "BOLD") == 0) { | |
3780 return "<b>"; | |
3781 } else if (strcmp(name, "ITALICS") == 0) { | |
3782 return "<i>"; | |
3783 } else if (strcmp(name, "UNDERLINE") == 0) { | |
3784 return "<u>"; | |
3785 } else if (strncmp(name, "LINK ", 5) == 0) { | |
3786 char *tmp = g_object_get_data(G_OBJECT(tag), "link_url"); | |
3787 if (tmp) { | |
3788 g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", tmp); | |
3789 buf[sizeof(buf)-1] = '\0'; | |
3790 return buf; | |
3791 } else { | |
3792 return ""; | |
3793 } | |
3794 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
3795 g_snprintf(buf, sizeof(buf), "<font color=\"%s\">", &name[10]); | |
3796 return buf; | |
3797 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
3798 g_snprintf(buf, sizeof(buf), "<font back=\"%s\">", &name[10]); | |
3799 return buf; | |
3800 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
3801 g_snprintf(buf, sizeof(buf), "<font face=\"%s\">", &name[10]); | |
3802 return buf; | |
3803 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
3804 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]); | |
3805 return buf; | |
3806 } else { | |
3807 return ""; | |
3808 } | |
8061 | 3809 } |
3810 | |
8677 | 3811 static const gchar *tag_to_html_end(GtkTextTag *tag) |
8061 | 3812 { |
8677 | 3813 const gchar *name; |
3814 | |
3815 name = tag->name; | |
3816 g_return_val_if_fail(name != NULL, ""); | |
3817 | |
3818 if (strcmp(name, "BOLD") == 0) { | |
3819 return "</b>"; | |
3820 } else if (strcmp(name, "ITALICS") == 0) { | |
3821 return "</i>"; | |
3822 } else if (strcmp(name, "UNDERLINE") == 0) { | |
3823 return "</u>"; | |
3824 } else if (strncmp(name, "LINK ", 5) == 0) { | |
3825 return "</a>"; | |
3826 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
3827 return "</font>"; | |
3828 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
3829 return "</font>"; | |
3830 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
3831 return "</font>"; | |
3832 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
3833 return "</font>"; | |
3834 } else { | |
3835 return ""; | |
3836 } | |
3837 } | |
3838 | |
3839 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) | |
3840 { | |
3841 return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) && | |
3842 !gtk_text_iter_has_tag(niter, GTK_TEXT_TAG(tag))) || | |
3843 gtk_text_iter_is_end(niter)); | |
8061 | 3844 } |
3845 | |
3846 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such | |
3847 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else | |
8677 | 3848 * check for tags that are toggled on, insert their html form, and push them on the queue. Then insert |
3849 * the actual text. Then check for tags that are toggled off and insert them, after checking the queue. | |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8729
diff
changeset
|
3850 * Finally, replace <, >, &, and " with their HTML equivalent. |
8677 | 3851 */ |
8061 | 3852 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) |
3853 { | |
3854 gunichar c; | |
8677 | 3855 GtkTextIter iter, nextiter; |
8061 | 3856 GString *str = g_string_new(""); |
8677 | 3857 GSList *tags, *sl; |
3858 GQueue *q, *r; | |
3859 GtkTextTag *tag; | |
3860 | |
3861 q = g_queue_new(); | |
3862 r = g_queue_new(); | |
3863 | |
8061 | 3864 |
3865 gtk_text_iter_order(start, end); | |
8677 | 3866 nextiter = iter = *start; |
3867 gtk_text_iter_forward_char(&nextiter); | |
3868 | |
9071 | 3869 /* First add the tags that are already in progress (we don't care about non-printing tags)*/ |
8677 | 3870 tags = gtk_text_iter_get_tags(start); |
3871 | |
3872 for (sl = tags; sl; sl = sl->next) { | |
3873 tag = sl->data; | |
3874 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { | |
9071 | 3875 if (strlen(tag_to_html_end(tag)) > 0) |
3876 g_string_append(str, tag_to_html_start(tag)); | |
8677 | 3877 g_queue_push_tail(q, tag); |
8061 | 3878 } |
3879 } | |
8677 | 3880 g_slist_free(tags); |
8061 | 3881 |
3882 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) { | |
8677 | 3883 |
3884 tags = gtk_text_iter_get_tags(&iter); | |
3885 | |
3886 for (sl = tags; sl; sl = sl->next) { | |
3887 tag = sl->data; | |
3888 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { | |
9071 | 3889 if (strlen(tag_to_html_end(tag)) > 0) |
3890 g_string_append(str, tag_to_html_start(tag)); | |
8677 | 3891 g_queue_push_tail(q, tag); |
3892 } | |
3893 } | |
3894 | |
3895 | |
8061 | 3896 if (c == 0xFFFC) { |
3897 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); | |
9071 | 3898 if (anchor) { |
3899 char *text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext"); | |
3900 if (text) | |
3901 str = g_string_append(str, text); | |
3902 } | |
8677 | 3903 } else if (c == '<') { |
3904 str = g_string_append(str, "<"); | |
3905 } else if (c == '>') { | |
3906 str = g_string_append(str, ">"); | |
3907 } else if (c == '&') { | |
3908 str = g_string_append(str, "&"); | |
3909 } else if (c == '"') { | |
3910 str = g_string_append(str, """); | |
3911 } else if (c == '\n') { | |
3912 str = g_string_append(str, "<br>"); | |
8061 | 3913 } else { |
8677 | 3914 str = g_string_append_unichar(str, c); |
3915 } | |
3916 | |
3917 tags = g_slist_reverse(tags); | |
3918 for (sl = tags; sl; sl = sl->next) { | |
3919 tag = sl->data; | |
9071 | 3920 /** don't worry about non-printing tags ending */ |
3921 if (tag_ends_here(tag, &iter, &nextiter) && strlen(tag_to_html_end(tag)) > 0) { | |
8677 | 3922 |
3923 GtkTextTag *tmp; | |
3924 | |
3925 while ((tmp = g_queue_pop_tail(q)) != tag) { | |
3926 if (tmp == NULL) | |
3927 break; | |
3928 | |
9071 | 3929 if (!tag_ends_here(tmp, &iter, &nextiter) && strlen(tag_to_html_end(tmp)) > 0) |
8677 | 3930 g_queue_push_tail(r, tmp); |
3931 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); | |
3932 } | |
3933 | |
3934 if (tmp == NULL) | |
3935 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); | |
3936 else | |
3937 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
3938 | |
3939 while ((tmp = g_queue_pop_head(r))) { | |
3940 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); | |
3941 g_queue_push_tail(q, tmp); | |
8061 | 3942 } |
3943 } | |
3944 } | |
8677 | 3945 |
3946 g_slist_free(tags); | |
8061 | 3947 gtk_text_iter_forward_char(&iter); |
8677 | 3948 gtk_text_iter_forward_char(&nextiter); |
8061 | 3949 } |
8677 | 3950 |
3951 while ((tag = g_queue_pop_tail(q))) | |
3952 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
3953 | |
3954 g_queue_free(q); | |
3955 g_queue_free(r); | |
8061 | 3956 return g_string_free(str, FALSE); |
3957 } | |
3958 | |
8698 | 3959 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter) |
8061 | 3960 { |
3961 if (imhtml->edit.bold) | |
3962 gtk_imhtml_toggle_bold(imhtml); | |
3963 | |
3964 if (imhtml->edit.italic) | |
3965 gtk_imhtml_toggle_italic(imhtml); | |
3966 | |
3967 if (imhtml->edit.underline) | |
3968 gtk_imhtml_toggle_underline(imhtml); | |
3969 | |
3970 if (imhtml->edit.forecolor) | |
3971 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
3972 | |
3973 if (imhtml->edit.backcolor) | |
3974 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
3975 | |
3976 if (imhtml->edit.fontface) | |
3977 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
3978 | |
8677 | 3979 imhtml->edit.fontsize = 0; |
3980 | |
8719 | 3981 if (imhtml->edit.link) |
3982 gtk_imhtml_toggle_link(imhtml, NULL); | |
3983 | |
8698 | 3984 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter); |
8061 | 3985 |
3986 } | |
3987 | |
3988 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) | |
3989 { | |
3990 GtkTextIter start, end; | |
3991 | |
3992 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
3993 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
3994 return gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
3995 } | |
3996 | |
8677 | 3997 char **gtk_imhtml_get_markup_lines(GtkIMHtml *imhtml) |
3998 { | |
3999 int i, j, lines; | |
4000 GtkTextIter start, end; | |
4001 char **ret; | |
4002 | |
4003 lines = gtk_text_buffer_get_line_count(imhtml->text_buffer); | |
4004 ret = g_new0(char *, lines + 1); | |
4005 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
4006 end = start; | |
4007 gtk_text_iter_forward_to_line_end(&end); | |
4008 | |
4009 for (i = 0, j = 0; i < lines; i++) { | |
4010 ret[j] = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
4011 if (ret[j] != NULL) | |
4012 j++; | |
4013 gtk_text_iter_forward_line(&start); | |
4014 end = start; | |
4015 gtk_text_iter_forward_to_line_end(&end); | |
4016 } | |
4017 | |
4018 return ret; | |
4019 } | |
4020 | |
4021 char *gtk_imhtml_get_text(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *stop) | |
8061 | 4022 { |
8519 | 4023 GString *str = g_string_new(""); |
4024 GtkTextIter iter, end; | |
4025 gunichar c; | |
4026 | |
8677 | 4027 if (start == NULL) |
4028 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
4029 else | |
4030 iter = *start; | |
4031 | |
4032 if (stop == NULL) | |
4033 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
4034 else | |
4035 end = *stop; | |
4036 | |
4037 gtk_text_iter_order(&iter, &end); | |
8519 | 4038 |
4039 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) { | |
4040 if (c == 0xFFFC) { | |
8677 | 4041 GtkTextChildAnchor* anchor; |
4042 char *text = NULL; | |
4043 | |
4044 anchor = gtk_text_iter_get_child_anchor(&iter); | |
4045 if (anchor) | |
8698 | 4046 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext"); |
8677 | 4047 if (text) |
4048 str = g_string_append(str, text); | |
8519 | 4049 } else { |
4050 g_string_append_unichar(str, c); | |
4051 } | |
4052 gtk_text_iter_forward_char(&iter); | |
4053 } | |
4054 | |
4055 return g_string_free(str, FALSE); | |
8061 | 4056 } |
8962 | 4057 |
4058 void gtk_imhtml_set_funcs(GtkIMHtml *imhtml, GtkIMHtmlFuncs *f) | |
4059 { | |
4060 g_return_if_fail(imhtml != NULL); | |
4061 imhtml->funcs = f; | |
4062 } |