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