Mercurial > pidgin.yaz
annotate src/gtkimhtml.c @ 9709:4d05b6e9e9cd
[gaim-migrate @ 10570]
This patch is freaking massive.
Renamed ui.h to gtkdialogs.h
Renamed dialogs.c to gtkdialogs.c
sed'ed the hell out of the .po files
These files are similar to gtkutil.c/.h. They are meant to contain
dialogs such as the "New Instant Message" window, which does not
belong in gtkblist.c or gtkconv.c, and is called from both places.
Eventually the functions in gtkdialogs.c/.h should be changed to
conform to Gaim's naming convention.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 08 Aug 2004 00:48:19 +0000 |
parents | d4634f26ef9b |
children | f105bc0270c7 |
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 | |
9709 | 62 /* GTK+ < 2.2.2 hack, see gtkdialogs.h for details. */ |
5105 | 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 } |
9621 | 839 |
8698 | 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 } | |
9636 | 1463 else if (*x == '<') /* Because we're all WYSIWYG now, a '<' |
1464 * char should only appear as the start of a tag. Perhaps a safer (but costlier) | |
1465 * check would be to call gtk_imhtml_is_tag on it */ | |
1466 return 0; | |
8505 | 1467 else |
1468 pos = strchr (t->values->str, *x); | |
1469 | |
4032 | 1470 if (pos) |
7371 | 1471 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1472 else |
1473 break; | |
1474 | |
1475 x++; len++; | |
1476 } | |
1477 | |
1478 if (t->image) | |
1479 return len; | |
1480 | |
1481 return 0; | |
1482 } | |
1483 | |
1484 void | |
4263 | 1485 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
1486 gchar *sml, | |
1487 GtkIMHtmlSmiley *smiley) | |
4032 | 1488 { |
1489 GtkSmileyTree *tree; | |
1490 g_return_if_fail (imhtml != NULL); | |
1491 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
7371 | 1492 |
4032 | 1493 if (sml == NULL) |
1494 tree = imhtml->default_smilies; | |
1495 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
1496 } else { | |
1497 tree = gtk_smiley_tree_new(); | |
4892 | 1498 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
4032 | 1499 } |
1500 | |
4263 | 1501 gtk_smiley_tree_insert (tree, smiley); |
4032 | 1502 } |
1503 | |
1504 static gboolean | |
1505 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
1506 GSList *fonts, | |
1507 const gchar *text, | |
1508 gint *len) | |
1509 { | |
1510 GtkSmileyTree *tree; | |
5967 | 1511 GtkIMHtmlFontDetail *font; |
4032 | 1512 char *sml = NULL; |
1513 | |
1514 if (fonts) { | |
1515 font = fonts->data; | |
1516 sml = font->sml; | |
1517 } | |
1518 | |
9029 | 1519 if (!sml) |
1520 sml = imhtml->protocol_name; | |
1521 | |
1522 if (!sml || !(tree = g_hash_table_lookup(imhtml->smiley_data, sml))) | |
4032 | 1523 tree = imhtml->default_smilies; |
9029 | 1524 |
4032 | 1525 if (tree == NULL) |
1526 return FALSE; | |
7371 | 1527 |
8505 | 1528 *len = gtk_smiley_tree_lookup (tree, text); |
4032 | 1529 return (*len > 0); |
1530 } | |
1531 | |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1532 GdkPixbufAnimation * |
4032 | 1533 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
1534 const gchar *sml, | |
1535 const gchar *text) | |
1536 { | |
1537 GtkSmileyTree *t; | |
1538 const gchar *x = text; | |
1539 if (sml == NULL) | |
1540 t = imhtml->default_smilies; | |
7371 | 1541 else |
4032 | 1542 t = g_hash_table_lookup(imhtml->smiley_data, sml); |
7371 | 1543 |
4032 | 1544 |
1545 if (t == NULL) | |
1546 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1547 | |
1548 while (*x) { | |
1549 gchar *pos; | |
1550 | |
1551 if (!t->values) { | |
1552 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1553 } | |
7371 | 1554 |
4032 | 1555 pos = strchr (t->values->str, *x); |
1556 if (pos) { | |
7371 | 1557 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1558 } else { |
1559 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1560 } | |
1561 x++; | |
1562 } | |
1563 | |
8890 | 1564 if (!t->image->file) |
1565 return NULL; | |
1566 | |
4263 | 1567 if (!t->image->icon) |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1568 t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); |
4263 | 1569 |
1570 return t->image->icon; | |
4032 | 1571 } |
8890 | 1572 |
4793 | 1573 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
3922 | 1574 *tag = g_strndup (string, strlen (x)); \ |
1575 *len = strlen (x) + 1; \ | |
1576 return TRUE; \ | |
1577 } \ | |
1578 (*type)++ | |
1428 | 1579 |
4793 | 1580 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
3922 | 1581 const gchar *c = string + strlen (x " "); \ |
1582 gchar e = '"'; \ | |
1583 gboolean quote = FALSE; \ | |
1584 while (*c) { \ | |
1585 if (*c == '"' || *c == '\'') { \ | |
1586 if (quote && (*c == e)) \ | |
1587 quote = !quote; \ | |
1588 else if (!quote) { \ | |
1589 quote = !quote; \ | |
1590 e = *c; \ | |
1591 } \ | |
1592 } else if (!quote && (*c == '>')) \ | |
1593 break; \ | |
1594 c++; \ | |
1595 } \ | |
1596 if (*c) { \ | |
1597 *tag = g_strndup (string, c - string); \ | |
1598 *len = c - string + 1; \ | |
1599 return TRUE; \ | |
1600 } \ | |
1601 } \ | |
1602 (*type)++ | |
1428 | 1603 |
1604 | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1605 static gboolean |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1606 gtk_imhtml_is_amp_escape (const gchar *string, |
7280 | 1607 gchar **replace, |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1608 gint *length) |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1609 { |
7287 | 1610 static char buf[7]; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1611 g_return_val_if_fail (string != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1612 g_return_val_if_fail (replace != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1613 g_return_val_if_fail (length != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1614 |
4793 | 1615 if (!g_ascii_strncasecmp (string, "&", 5)) { |
7280 | 1616 *replace = "&"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1617 *length = 5; |
4793 | 1618 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
7280 | 1619 *replace = "<"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1620 *length = 4; |
4793 | 1621 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
7280 | 1622 *replace = ">"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1623 *length = 4; |
4793 | 1624 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
7280 | 1625 *replace = " "; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1626 *length = 6; |
4793 | 1627 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
7280 | 1628 *replace = "©"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1629 *length = 6; |
4793 | 1630 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
7280 | 1631 *replace = "\""; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1632 *length = 6; |
4793 | 1633 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
7280 | 1634 *replace = "®"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1635 *length = 5; |
5093 | 1636 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
7280 | 1637 *replace = "\'"; |
5093 | 1638 *length = 6; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1639 } else if (*(string + 1) == '#') { |
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
1640 guint pound = 0; |
3004 | 1641 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
7287 | 1642 int buflen; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1643 if (*(string + 3 + (gint)log10 (pound)) != ';') |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1644 return FALSE; |
7287 | 1645 buflen = g_unichar_to_utf8((gunichar)pound, buf); |
1646 buf[buflen] = '\0'; | |
7280 | 1647 *replace = buf; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1648 *length = 2; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1649 while (isdigit ((gint) string [*length])) (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1650 if (string [*length] == ';') (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1651 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1652 return FALSE; |
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 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1655 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1656 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1657 |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1658 return TRUE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1659 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1660 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1661 static gboolean |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1662 gtk_imhtml_is_tag (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1663 gchar **tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1664 gint *len, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1665 gint *type) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1666 { |
8061 | 1667 char *close; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1668 *type = 1; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1669 |
8118 | 1670 |
8061 | 1671 if (!(close = strchr (string, '>'))) |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1672 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1673 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1674 VALID_TAG ("B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1675 VALID_TAG ("BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1676 VALID_TAG ("/B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1677 VALID_TAG ("/BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1678 VALID_TAG ("I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1679 VALID_TAG ("ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1680 VALID_TAG ("/I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1681 VALID_TAG ("/ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1682 VALID_TAG ("U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1683 VALID_TAG ("UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1684 VALID_TAG ("/U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1685 VALID_TAG ("/UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1686 VALID_TAG ("S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1687 VALID_TAG ("STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1688 VALID_TAG ("/S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1689 VALID_TAG ("/STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1690 VALID_TAG ("SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1691 VALID_TAG ("/SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1692 VALID_TAG ("SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1693 VALID_TAG ("/SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1694 VALID_TAG ("PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1695 VALID_TAG ("/PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1696 VALID_TAG ("TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1697 VALID_TAG ("/TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1698 VALID_TAG ("BR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1699 VALID_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1700 VALID_TAG ("/FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1701 VALID_TAG ("/A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1702 VALID_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1703 VALID_TAG ("/P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1704 VALID_TAG ("H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1705 VALID_TAG ("/H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1706 VALID_TAG ("HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1707 VALID_TAG ("/HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1708 VALID_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1709 VALID_TAG ("/BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1710 VALID_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1711 VALID_TAG ("HEAD"); |
2993 | 1712 VALID_TAG ("/HEAD"); |
1713 VALID_TAG ("BINARY"); | |
1714 VALID_TAG ("/BINARY"); | |
5093 | 1715 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1716 VALID_OPT_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1717 VALID_OPT_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1718 VALID_OPT_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1719 VALID_OPT_TAG ("A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1720 VALID_OPT_TAG ("IMG"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1721 VALID_OPT_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1722 VALID_OPT_TAG ("H3"); |
5093 | 1723 VALID_OPT_TAG ("HTML"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1724 |
5101 | 1725 VALID_TAG ("CITE"); |
1726 VALID_TAG ("/CITE"); | |
1727 VALID_TAG ("EM"); | |
1728 VALID_TAG ("/EM"); | |
1729 VALID_TAG ("STRONG"); | |
1730 VALID_TAG ("/STRONG"); | |
1731 | |
5104 | 1732 VALID_OPT_TAG ("SPAN"); |
1733 VALID_TAG ("/SPAN"); | |
5174 | 1734 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
6982 | 1735 VALID_TAG ("IMG"); |
8026 | 1736 VALID_TAG("SPAN"); |
8061 | 1737 VALID_OPT_TAG("BR"); |
7988 | 1738 |
4793 | 1739 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
1740 gchar *e = strstr (string + strlen("!--"), "-->"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1741 if (e) { |
9700 | 1742 *type = -1; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1743 *len = e - string + strlen ("-->"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1744 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1745 return TRUE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1746 } |
8118 | 1747 } |
1748 | |
8061 | 1749 *type = -1; |
1750 *len = close - string + 1; | |
1751 *tag = g_strndup(string, *len - 1); | |
1752 return TRUE; | |
2856
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 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1755 static gchar* |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1756 gtk_imhtml_get_html_opt (gchar *tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1757 const gchar *opt) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1758 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1759 gchar *t = tag; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1760 gchar *e, *a; |
5177 | 1761 gchar *val; |
1762 gint len; | |
7280 | 1763 gchar *c; |
5177 | 1764 GString *ret; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1765 |
4793 | 1766 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1767 gboolean quote = FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1768 if (*t == '\0') break; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1769 while (*t && !((*t == ' ') && !quote)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1770 if (*t == '\"') |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1771 quote = ! quote; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1772 t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1773 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1774 while (*t && (*t == ' ')) t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1775 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1776 |
4793 | 1777 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1778 t += strlen (opt); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1779 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1780 return NULL; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1781 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1782 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1783 if ((*t == '\"') || (*t == '\'')) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1784 e = a = ++t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1785 while (*e && (*e != *(t - 1))) e++; |
2993 | 1786 if (*e == '\0') { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1787 return NULL; |
5177 | 1788 } else |
1789 val = g_strndup(a, e - a); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1790 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1791 e = a = t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1792 while (*e && !isspace ((gint) *e)) e++; |
5177 | 1793 val = g_strndup(a, e - a); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1794 } |
5177 | 1795 |
1796 ret = g_string_new(""); | |
1797 e = val; | |
1798 while(*e) { | |
1799 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
7280 | 1800 ret = g_string_append(ret, c); |
5177 | 1801 e += len; |
1802 } else { | |
1803 ret = g_string_append_c(ret, *e); | |
1804 e++; | |
1805 } | |
1806 } | |
1807 | |
1808 g_free(val); | |
8568 | 1809 |
1810 return g_string_free(ret, FALSE); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1811 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1812 |
8118 | 1813 /* Inline CSS Support - Douglas Thrift */ |
1814 static gchar* | |
1815 gtk_imhtml_get_css_opt (gchar *style, | |
1816 const gchar *opt) | |
1817 { | |
1818 gchar *t = style; | |
1819 gchar *e, *a; | |
1820 gchar *val; | |
1821 gint len; | |
1822 gchar *c; | |
1823 GString *ret; | |
1824 | |
1825 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
8177 | 1826 /* gboolean quote = FALSE; */ |
8118 | 1827 if (*t == '\0') break; |
1828 while (*t && !((*t == ' ') /*&& !quote*/)) { | |
1829 /* if (*t == '\"') | |
8177 | 1830 quote = ! quote; */ |
8118 | 1831 t++; |
1832 } | |
1833 while (*t && (*t == ' ')) t++; | |
1834 } | |
1835 | |
1836 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
1837 t += strlen (opt); | |
1838 } else { | |
1839 return NULL; | |
1840 } | |
1841 | |
1842 /* if ((*t == '\"') || (*t == '\'')) { | |
1843 e = a = ++t; | |
1844 while (*e && (*e != *(t - 1))) e++; | |
1845 if (*e == '\0') { | |
1846 return NULL; | |
1847 } else | |
1848 val = g_strndup(a, e - a); | |
1849 } else { | |
1850 e = a = t; | |
1851 while (*e && !isspace ((gint) *e)) e++; | |
1852 val = g_strndup(a, e - a); | |
1853 }*/ | |
1854 | |
1855 e = a = t; | |
1856 while (*e && *e != ';') e++; | |
1857 val = g_strndup(a, e - a); | |
1858 | |
1859 ret = g_string_new(""); | |
1860 e = val; | |
1861 while(*e) { | |
1862 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
1863 ret = g_string_append(ret, c); | |
1864 e += len; | |
1865 } else { | |
1866 ret = g_string_append_c(ret, *e); | |
1867 e++; | |
1868 } | |
1869 } | |
1870 | |
1871 g_free(val); | |
1872 val = ret->str; | |
1873 g_string_free(ret, FALSE); | |
1874 return val; | |
1875 } | |
3922 | 1876 |
8334 | 1877 static const char *accepted_protocols[] = { |
1878 "http://", | |
1879 "https://", | |
1880 "ftp://" | |
1881 }; | |
1882 | |
1883 static const int accepted_protocols_size = 3; | |
1884 | |
1885 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so | |
1886 the caller knows how long the protocol string is. */ | |
1887 int gtk_imhtml_is_protocol(const char *text) | |
1888 { | |
1889 gint i; | |
1890 | |
1891 for(i=0; i<accepted_protocols_size; i++){ | |
1892 if( strncasecmp(text, accepted_protocols[i], strlen(accepted_protocols[i])) == 0 ){ | |
1893 return strlen(accepted_protocols[i]); | |
1894 } | |
1895 } | |
1896 return 0; | |
1897 } | |
1898 | |
8677 | 1899 /* |
1900 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming | |
1901 | |
1902 | |
1903 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :) | |
1904 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/> | |
1905 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz | |
1906 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add | |
1907 [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? | |
1908 [20:00] <KingAnt> marv: Right | |
1909 [20:00] <marv> alright | |
1910 | |
1911 Here's my plan with IMImages. make gtk_imhtml_[append|insert]_text_with_images instead just | |
1912 gtkimhtml_[append|insert]_text (hrm maybe it should be called html instead of text), add a | |
1913 function for gaim to register for look up images, i.e. gtk_imhtml_set_get_img_fnc, so that | |
1914 images can be looked up like that, instead of passing a GSList of them. | |
1915 */ | |
1916 | |
1917 void gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, | |
1918 const gchar *text, | |
1919 GtkIMHtmlOptions options, | |
1920 GSList *unused) | |
1428 | 1921 { |
8677 | 1922 GtkTextIter iter, ins, sel; |
1923 GdkRectangle rect; | |
1924 int y, height, ins_offset = 0, sel_offset = 0; | |
1925 gboolean fixins = FALSE, fixsel = FALSE; | |
1926 | |
1927 g_return_if_fail (imhtml != NULL); | |
1928 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1929 g_return_if_fail (text != NULL); | |
1930 | |
1931 | |
1932 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1933 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, gtk_text_buffer_get_insert(imhtml->text_buffer)); | |
1934 if (gtk_text_iter_equal(&iter, &ins) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1935 fixins = TRUE; | |
1936 ins_offset = gtk_text_iter_get_offset(&ins); | |
1937 } | |
1938 | |
1939 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &sel, gtk_text_buffer_get_selection_bound(imhtml->text_buffer)); | |
1940 if (gtk_text_iter_equal(&iter, &sel) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1941 fixsel = TRUE; | |
1942 sel_offset = gtk_text_iter_get_offset(&sel); | |
1943 } | |
1944 | |
1945 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1946 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); | |
1947 | |
1948 | |
1949 if(((y + height) - (rect.y + rect.height)) > height | |
1950 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ | |
1951 options |= GTK_IMHTML_NO_SCROLL; | |
1952 } | |
1953 | |
1954 gtk_imhtml_insert_html_at_iter(imhtml, text, options, &iter); | |
1955 | |
1956 if (fixins) { | |
1957 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins, ins_offset); | |
1958 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_insert(imhtml->text_buffer), &ins); | |
1959 } | |
1960 | |
1961 if (fixsel) { | |
1962 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &sel, sel_offset); | |
1963 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_selection_bound(imhtml->text_buffer), &sel); | |
1964 } | |
1965 | |
1966 if (!(options & GTK_IMHTML_NO_SCROLL)) { | |
8729 | 1967 gtk_imhtml_scroll_to_end(imhtml); |
8677 | 1968 } |
1969 } | |
1970 | |
8729 | 1971 void gtk_imhtml_scroll_to_end(GtkIMHtml *imhtml) |
1972 { | |
1973 GtkTextIter iter; | |
1974 /* If this seems backwards at first glance, well it's not. | |
1975 * It means scroll such that the mark is closest to the top, | |
1976 * and closest to the right as possible. Remember kids, you have | |
1977 * to scroll left to move a given spot closest to the right, | |
1978 * and scroll down to move a spot closest to the top. | |
1979 */ | |
1980 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1981 gtk_text_iter_set_line_offset(&iter, 0); | |
1982 gtk_text_buffer_move_mark(imhtml->text_buffer, imhtml->scrollpoint, &iter); | |
1983 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), imhtml->scrollpoint, | |
1984 0, TRUE, 1.0, 0.0); | |
1985 } | |
1986 | |
8677 | 1987 void gtk_imhtml_insert_html_at_iter(GtkIMHtml *imhtml, |
1988 const gchar *text, | |
1989 GtkIMHtmlOptions options, | |
1990 GtkTextIter *iter) | |
1991 { | |
8061 | 1992 GdkRectangle rect; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1993 gint pos = 0; |
3922 | 1994 gchar *ws; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1995 gchar *tag; |
3922 | 1996 gchar *bg = NULL; |
6982 | 1997 gint len; |
4032 | 1998 gint tlen, smilelen, wpos=0; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1999 gint type; |
3922 | 2000 const gchar *c; |
7280 | 2001 gchar *amp; |
8334 | 2002 gint len_protocol; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2003 |
1428 | 2004 guint bold = 0, |
2005 italics = 0, | |
2006 underline = 0, | |
2007 strike = 0, | |
2008 sub = 0, | |
2009 sup = 0, | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2010 title = 0, |
8061 | 2011 pre = 0; |
1428 | 2012 |
3922 | 2013 GSList *fonts = NULL; |
8506 | 2014 GObject *object; |
8061 | 2015 GtkIMHtmlScalable *scalable = NULL; |
8677 | 2016 |
2017 g_return_if_fail (imhtml != NULL); | |
2018 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2019 g_return_if_fail (text != NULL); | |
3922 | 2020 c = text; |
6982 | 2021 len = strlen(text); |
3922 | 2022 ws = g_malloc(len + 1); |
2023 ws[0] = 0; | |
1428 | 2024 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2025 while (pos < len) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2026 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2027 c++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2028 pos++; |
8061 | 2029 ws[wpos] = '\0'; |
2030 switch (type) | |
3922 | 2031 { |
2032 case 1: /* B */ | |
2033 case 2: /* BOLD */ | |
5101 | 2034 case 54: /* STRONG */ |
8677 | 2035 |
2036 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
2037 | |
2038 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD)) | |
8061 | 2039 gtk_imhtml_toggle_bold(imhtml); |
3922 | 2040 bold++; |
8061 | 2041 ws[0] = '\0'; wpos = 0; |
3922 | 2042 break; |
2043 case 3: /* /B */ | |
2044 case 4: /* /BOLD */ | |
5101 | 2045 case 55: /* /STRONG */ |
8677 | 2046 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2047 ws[0] = '\0'; wpos = 0; |
2048 | |
3922 | 2049 if (bold) |
2050 bold--; | |
8677 | 2051 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD) && !imhtml->wbfo) |
8061 | 2052 gtk_imhtml_toggle_bold(imhtml); |
3922 | 2053 break; |
2054 case 5: /* I */ | |
2055 case 6: /* ITALIC */ | |
5101 | 2056 case 52: /* EM */ |
8677 | 2057 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2058 ws[0] = '\0'; wpos = 0; |
8677 | 2059 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC)) |
8061 | 2060 gtk_imhtml_toggle_italic(imhtml); |
3922 | 2061 italics++; |
2062 break; | |
2063 case 7: /* /I */ | |
2064 case 8: /* /ITALIC */ | |
5101 | 2065 case 53: /* /EM */ |
8677 | 2066 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2067 ws[0] = '\0'; wpos = 0; |
3922 | 2068 if (italics) |
2069 italics--; | |
8677 | 2070 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC) && !imhtml->wbfo) |
8061 | 2071 gtk_imhtml_toggle_italic(imhtml); |
3922 | 2072 break; |
2073 case 9: /* U */ | |
2074 case 10: /* UNDERLINE */ | |
8677 | 2075 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2076 ws[0] = '\0'; wpos = 0; |
8677 | 2077 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
8061 | 2078 gtk_imhtml_toggle_underline(imhtml); |
3922 | 2079 underline++; |
2080 break; | |
2081 case 11: /* /U */ | |
2082 case 12: /* /UNDERLINE */ | |
8677 | 2083 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2084 ws[0] = '\0'; wpos = 0; |
3922 | 2085 if (underline) |
2086 underline--; | |
8677 | 2087 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE) && !imhtml->wbfo) |
8061 | 2088 gtk_imhtml_toggle_underline(imhtml); |
3922 | 2089 break; |
2090 case 13: /* S */ | |
2091 case 14: /* STRIKE */ | |
8677 | 2092 /* FIXME: reimplement this */ |
3922 | 2093 strike++; |
2094 break; | |
2095 case 15: /* /S */ | |
2096 case 16: /* /STRIKE */ | |
8677 | 2097 /* FIXME: reimplement this */ |
3922 | 2098 if (strike) |
2099 strike--; | |
2100 break; | |
2101 case 17: /* SUB */ | |
8677 | 2102 /* FIXME: reimpliment this */ |
3922 | 2103 sub++; |
2104 break; | |
2105 case 18: /* /SUB */ | |
8677 | 2106 /* FIXME: reimpliment this */ |
3922 | 2107 if (sub) |
2108 sub--; | |
2109 break; | |
2110 case 19: /* SUP */ | |
8677 | 2111 /* FIXME: reimplement this */ |
3922 | 2112 sup++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2113 break; |
3922 | 2114 case 20: /* /SUP */ |
8677 | 2115 /* FIXME: reimplement this */ |
3922 | 2116 if (sup) |
2117 sup--; | |
2118 break; | |
2119 case 21: /* PRE */ | |
8677 | 2120 /* FIXME: reimplement this */ |
3922 | 2121 pre++; |
2122 break; | |
2123 case 22: /* /PRE */ | |
8677 | 2124 /* FIXME: reimplement this */ |
3922 | 2125 if (pre) |
2126 pre--; | |
2127 break; | |
2128 case 23: /* TITLE */ | |
8677 | 2129 /* FIXME: what was this supposed to do anyway? */ |
3922 | 2130 title++; |
2131 break; | |
2132 case 24: /* /TITLE */ | |
8677 | 2133 /* FIXME: make this undo whatever 23 was supposed to do */ |
3922 | 2134 if (title) { |
2135 if (options & GTK_IMHTML_NO_TITLE) { | |
2136 wpos = 0; | |
2137 ws [wpos] = '\0'; | |
2138 } | |
2139 title--; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2140 } |
3922 | 2141 break; |
2142 case 25: /* BR */ | |
5174 | 2143 case 58: /* BR/ */ |
8061 | 2144 case 61: /* BR (opt) */ |
3922 | 2145 ws[wpos] = '\n'; |
2146 wpos++; | |
6982 | 2147 break; |
3922 | 2148 case 26: /* HR */ |
2149 case 42: /* HR (opt) */ | |
8726 | 2150 { |
2151 int minus; | |
2152 | |
3922 | 2153 ws[wpos++] = '\n'; |
8677 | 2154 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2155 | |
5967 | 2156 scalable = gtk_imhtml_hr_new(); |
8061 | 2157 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
8677 | 2158 scalable->add_to(scalable, imhtml, iter); |
8726 | 2159 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + |
2160 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
2161 scalable->scale(scalable, rect.width - minus, rect.height); | |
8061 | 2162 imhtml->scalables = g_list_append(imhtml->scalables, scalable); |
2163 ws[0] = '\0'; wpos = 0; | |
7942 | 2164 ws[wpos++] = '\n'; |
8061 | 2165 |
3922 | 2166 break; |
8726 | 2167 } |
3922 | 2168 case 27: /* /FONT */ |
8677 | 2169 if (fonts && !imhtml->wbfo) { |
5967 | 2170 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 2171 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2172 ws[0] = '\0'; wpos = 0; |
8177 | 2173 /* NEW_BIT (NEW_TEXT_BIT); */ |
8677 | 2174 |
8698 | 2175 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) { |
8061 | 2176 gtk_imhtml_toggle_fontface(imhtml, NULL); |
3922 | 2177 g_free (font->face); |
8061 | 2178 } |
8698 | 2179 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
8061 | 2180 gtk_imhtml_toggle_forecolor(imhtml, NULL); |
3922 | 2181 g_free (font->fore); |
8061 | 2182 } |
8698 | 2183 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
8061 | 2184 gtk_imhtml_toggle_backcolor(imhtml, NULL); |
3922 | 2185 g_free (font->back); |
8061 | 2186 } |
4032 | 2187 if (font->sml) |
2188 g_free (font->sml); | |
8309 | 2189 |
8698 | 2190 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 2191 gtk_imhtml_font_set_size(imhtml, 3); |
2192 | |
9245 | 2193 g_free(font); |
2194 | |
8309 | 2195 fonts = fonts->next; |
2196 if (fonts) { | |
2197 GtkIMHtmlFontDetail *font = fonts->data; | |
8677 | 2198 |
8698 | 2199 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8309 | 2200 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8698 | 2201 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8309 | 2202 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8698 | 2203 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
8309 | 2204 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8698 | 2205 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 2206 gtk_imhtml_font_set_size(imhtml, font->size); |
2207 } | |
3922 | 2208 } |
8309 | 2209 break; |
3922 | 2210 case 28: /* /A */ |
8677 | 2211 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2212 gtk_imhtml_toggle_link(imhtml, NULL); | |
2213 ws[0] = '\0'; wpos = 0; | |
8061 | 2214 break; |
8118 | 2215 |
3922 | 2216 case 29: /* P */ |
2217 case 30: /* /P */ | |
2218 case 31: /* H3 */ | |
2219 case 32: /* /H3 */ | |
2220 case 33: /* HTML */ | |
2221 case 34: /* /HTML */ | |
2222 case 35: /* BODY */ | |
2223 case 36: /* /BODY */ | |
2224 case 37: /* FONT */ | |
2225 case 38: /* HEAD */ | |
2226 case 39: /* /HEAD */ | |
6982 | 2227 case 40: /* BINARY */ |
2228 case 41: /* /BINARY */ | |
3922 | 2229 break; |
2230 case 43: /* FONT (opt) */ | |
2231 { | |
4032 | 2232 gchar *color, *back, *face, *size, *sml; |
5967 | 2233 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
3922 | 2234 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
2235 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
2236 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
2237 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
4032 | 2238 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
2239 if (!(color || back || face || size || sml)) | |
3922 | 2240 break; |
8061 | 2241 |
8677 | 2242 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2243 ws[0] = '\0'; wpos = 0; |
2244 | |
5967 | 2245 font = g_new0 (GtkIMHtmlFontDetail, 1); |
3922 | 2246 if (fonts) |
2247 oldfont = fonts->data; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2248 |
8677 | 2249 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
3922 | 2250 font->fore = color; |
8061 | 2251 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8677 | 2252 } |
8309 | 2253 //else if (oldfont && oldfont->fore) |
2254 // font->fore = g_strdup(oldfont->fore); | |
8677 | 2255 |
2256 if (back && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { | |
3922 | 2257 font->back = back; |
8061 | 2258 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8309 | 2259 } |
2260 //else if (oldfont && oldfont->back) | |
2261 // font->back = g_strdup(oldfont->back); | |
8677 | 2262 |
2263 if (face && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) { | |
3922 | 2264 font->face = face; |
8061 | 2265 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8309 | 2266 } |
2267 //else if (oldfont && oldfont->face) | |
2268 // font->face = g_strdup(oldfont->face); | |
4032 | 2269 |
2270 if (sml) | |
2271 font->sml = sml; | |
2272 else if (oldfont && oldfont->sml) | |
2273 font->sml = g_strdup(oldfont->sml); | |
2274 | |
8677 | 2275 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) { |
3922 | 2276 if (*size == '+') { |
2277 sscanf (size + 1, "%hd", &font->size); | |
2278 font->size += 3; | |
2279 } else if (*size == '-') { | |
2280 sscanf (size + 1, "%hd", &font->size); | |
2281 font->size = MAX (0, 3 - font->size); | |
2282 } else if (isdigit (*size)) { | |
2283 sscanf (size, "%hd", &font->size); | |
8061 | 2284 } |
6042 | 2285 if (font->size > 100) |
2286 font->size = 100; | |
3922 | 2287 } else if (oldfont) |
2288 font->size = oldfont->size; | |
8309 | 2289 else |
2290 font->size = 3; | |
8698 | 2291 if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
2292 gtk_imhtml_font_set_size(imhtml, font->size); | |
3922 | 2293 g_free(size); |
2294 fonts = g_slist_prepend (fonts, font); | |
2295 } | |
2296 break; | |
2297 case 44: /* BODY (opt) */ | |
2298 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
2299 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
8677 | 2300 if (bgcolor && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
2301 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2302 ws[0] = '\0'; wpos = 0; |
8177 | 2303 /* NEW_BIT(NEW_TEXT_BIT); */ |
3922 | 2304 if (bg) |
2305 g_free(bg); | |
2306 bg = bgcolor; | |
8061 | 2307 gtk_imhtml_toggle_backcolor(imhtml, bg); |
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
2308 } |
1428 | 2309 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2310 break; |
3922 | 2311 case 45: /* A (opt) */ |
2312 { | |
2313 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
8677 | 2314 if (href && (imhtml->format_functions & GTK_IMHTML_LINK)) { |
2315 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2316 ws[0] = '\0'; wpos = 0; |
8677 | 2317 gtk_imhtml_toggle_link(imhtml, href); |
3922 | 2318 } |
2993 | 2319 } |
3922 | 2320 break; |
4895 | 2321 case 46: /* IMG (opt) */ |
6982 | 2322 case 59: /* IMG */ |
4895 | 2323 { |
8962 | 2324 const char *id; |
2325 | |
2326 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
2327 ws[0] = '\0'; wpos = 0; | |
4895 | 2328 |
8677 | 2329 if (!(imhtml->format_functions & GTK_IMHTML_IMAGE)) |
2330 break; | |
2331 | |
8962 | 2332 id = gtk_imhtml_get_html_opt(tag, "ID="); |
9186 | 2333 if (!id) |
2334 break; | |
8962 | 2335 gtk_imhtml_insert_image_at_iter(imhtml, atoi(id), iter); |
2336 break; | |
4895 | 2337 } |
3922 | 2338 case 47: /* P (opt) */ |
2339 case 48: /* H3 (opt) */ | |
5093 | 2340 case 49: /* HTML (opt) */ |
5101 | 2341 case 50: /* CITE */ |
2342 case 51: /* /CITE */ | |
8026 | 2343 case 56: /* SPAN (opt) */ |
8118 | 2344 /* Inline CSS Support - Douglas Thrift |
2345 * | |
2346 * color | |
8686 | 2347 * background |
8118 | 2348 * font-family |
2349 * font-size | |
8686 | 2350 * text-decoration: underline |
8118 | 2351 */ |
2352 { | |
8686 | 2353 gchar *style, *color, *background, *family, *size; |
2354 gchar *textdec; | |
8118 | 2355 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
2356 style = gtk_imhtml_get_html_opt (tag, "style="); | |
2357 | |
2358 if (!style) break; | |
2359 | |
2360 color = gtk_imhtml_get_css_opt (style, "color: "); | |
8686 | 2361 background = gtk_imhtml_get_css_opt (style, "background: "); |
8118 | 2362 family = gtk_imhtml_get_css_opt (style, |
2363 "font-family: "); | |
2364 size = gtk_imhtml_get_css_opt (style, "font-size: "); | |
8686 | 2365 textdec = gtk_imhtml_get_css_opt (style, "text-decoration: "); |
2366 | |
2367 if (!(color || family || size || background || textdec)) { | |
8120 | 2368 g_free(style); |
2369 break; | |
2370 } | |
8118 | 2371 |
8677 | 2372 |
2373 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8118 | 2374 ws[0] = '\0'; wpos = 0; |
8177 | 2375 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2376 |
2377 font = g_new0 (GtkIMHtmlFontDetail, 1); | |
2378 if (fonts) | |
2379 oldfont = fonts->data; | |
2380 | |
8677 | 2381 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8686 | 2382 { |
8118 | 2383 font->fore = color; |
8686 | 2384 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
2385 } | |
8118 | 2386 else if (oldfont && oldfont->fore) |
2387 font->fore = g_strdup(oldfont->fore); | |
2388 | |
8686 | 2389 if (background && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
2390 { | |
2391 font->back = background; | |
2392 gtk_imhtml_toggle_backcolor(imhtml, font->back); | |
2393 } | |
2394 else if (oldfont && oldfont->back) | |
8118 | 2395 font->back = g_strdup(oldfont->back); |
2396 | |
8677 | 2397 if (family && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8686 | 2398 { |
8118 | 2399 font->face = family; |
8686 | 2400 gtk_imhtml_toggle_fontface(imhtml, font->face); |
2401 } | |
8118 | 2402 else if (oldfont && oldfont->face) |
2403 font->face = g_strdup(oldfont->face); | |
2404 if (font->face && (atoi(font->face) > 100)) { | |
8677 | 2405 /* WTF is this? */ |
9696 | 2406 /* Maybe it sets a max size on the font face? I seem to |
2407 * remember bad things happening if the font size was | |
2408 * 2 billion */ | |
8118 | 2409 g_free(font->face); |
2410 font->face = g_strdup("100"); | |
2411 } | |
2412 | |
2413 if (oldfont && oldfont->sml) | |
2414 font->sml = g_strdup(oldfont->sml); | |
2415 | |
8677 | 2416 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_SHRINK|GTK_IMHTML_GROW))) { |
8686 | 2417 if (g_ascii_strcasecmp(size, "xx-small") == 0) |
2418 font->size = 1; | |
2419 else if (g_ascii_strcasecmp(size, "smaller") == 0 | |
2420 || g_ascii_strcasecmp(size, "x-small") == 0) | |
8118 | 2421 font->size = 2; |
8686 | 2422 else if (g_ascii_strcasecmp(size, "larger") == 0 |
2423 || g_ascii_strcasecmp(size, "medium") == 0) | |
8118 | 2424 font->size = 4; |
8686 | 2425 else if (g_ascii_strcasecmp(size, "large") == 0) |
2426 font->size = 5; | |
2427 else if (g_ascii_strcasecmp(size, "x-large") == 0) | |
2428 font->size = 6; | |
2429 else if (g_ascii_strcasecmp(size, "xx-large") == 0) | |
2430 font->size = 7; | |
8118 | 2431 else |
2432 font->size = 3; | |
8686 | 2433 gtk_imhtml_font_set_size(imhtml, font->size); |
2434 } | |
2435 else if (oldfont) | |
2436 { | |
2437 font->size = oldfont->size; | |
2438 } | |
2439 | |
2440 if (oldfont) | |
2441 { | |
2442 font->underline = oldfont->underline; | |
2443 } | |
2444 if (textdec && font->underline != 1 | |
9025 | 2445 && g_ascii_strcasecmp(textdec, "underline") == 0 |
8686 | 2446 && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
2447 { | |
2448 gtk_imhtml_toggle_underline(imhtml); | |
2449 font->underline = 1; | |
2450 } | |
8118 | 2451 |
2452 g_free(style); | |
2453 g_free(size); | |
2454 fonts = g_slist_prepend (fonts, font); | |
2455 } | |
2456 break; | |
5104 | 2457 case 57: /* /SPAN */ |
8118 | 2458 /* Inline CSS Support - Douglas Thrift */ |
8677 | 2459 if (fonts && !imhtml->wbfo) { |
8686 | 2460 GtkIMHtmlFontDetail *oldfont = NULL; |
8118 | 2461 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 2462 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8118 | 2463 ws[0] = '\0'; wpos = 0; |
8177 | 2464 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2465 fonts = g_slist_remove (fonts, font); |
8692 | 2466 if (fonts) |
2467 oldfont = fonts->data; | |
2468 | |
2469 if (!oldfont) { | |
2470 gtk_imhtml_font_set_size(imhtml, 3); | |
2471 if (font->underline) | |
2472 gtk_imhtml_toggle_underline(imhtml); | |
2473 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
2474 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
2475 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
8686 | 2476 } |
8692 | 2477 else |
8686 | 2478 { |
8692 | 2479 |
2480 if (font->size != oldfont->size) | |
2481 gtk_imhtml_font_set_size(imhtml, oldfont->size); | |
2482 | |
2483 if (font->underline != oldfont->underline) | |
2484 gtk_imhtml_toggle_underline(imhtml); | |
2485 | |
9286 | 2486 if (font->face && (!oldfont->face || strcmp(font->face, oldfont->face) != 0)) |
8692 | 2487 gtk_imhtml_toggle_fontface(imhtml, oldfont->face); |
2488 | |
9286 | 2489 if (font->fore && (!oldfont->fore || strcmp(font->fore, oldfont->fore) != 0)) |
8692 | 2490 gtk_imhtml_toggle_forecolor(imhtml, oldfont->fore); |
2491 | |
9286 | 2492 if (font->back && (!oldfont->back || strcmp(font->back, oldfont->back) != 0)) |
8692 | 2493 gtk_imhtml_toggle_backcolor(imhtml, oldfont->back); |
8686 | 2494 } |
8692 | 2495 |
2496 g_free (font->face); | |
2497 g_free (font->fore); | |
2498 g_free (font->back); | |
2499 g_free (font->sml); | |
2500 | |
8118 | 2501 g_free (font); |
2502 } | |
2503 break; | |
8026 | 2504 case 60: /* SPAN */ |
2993 | 2505 break; |
8061 | 2506 case 62: /* comment */ |
8177 | 2507 /* NEW_BIT (NEW_TEXT_BIT); */ |
8317 | 2508 ws[wpos] = '\0'; |
9465 | 2509 |
8677 | 2510 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2511 | |
9465 | 2512 if (imhtml->show_comments && !(options & GTK_IMHTML_NO_COMMENTS)) |
6124 | 2513 wpos = g_snprintf (ws, len, "%s", tag); |
8177 | 2514 /* NEW_BIT (NEW_COMMENT_BIT); */ |
3922 | 2515 break; |
2516 default: | |
6882 | 2517 break; |
2993 | 2518 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2519 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2520 pos += tlen; |
4138 | 2521 if(tag) |
2522 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
9029 | 2523 } else if (gtk_imhtml_is_smiley(imhtml, fonts, c, &smilelen)) { |
8473 | 2524 GtkIMHtmlFontDetail *fd; |
2525 | |
2526 gchar *sml = NULL; | |
2527 if (fonts) { | |
2528 fd = fonts->data; | |
2529 sml = fd->sml; | |
2530 } | |
9029 | 2531 if (!sml) |
2532 sml = imhtml->protocol_name; | |
2533 | |
8677 | 2534 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8505 | 2535 wpos = g_snprintf (ws, smilelen + 1, "%s", c); |
8473 | 2536 |
8677 | 2537 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, ws, iter); |
8473 | 2538 |
8505 | 2539 c += smilelen; |
2540 pos += smilelen; | |
8473 | 2541 wpos = 0; |
2542 ws[0] = 0; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2543 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
7280 | 2544 while(*amp) { |
2545 ws [wpos++] = *amp++; | |
2546 } | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2547 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2548 pos += tlen; |
1428 | 2549 } else if (*c == '\n') { |
2550 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
3922 | 2551 ws[wpos] = '\n'; |
2552 wpos++; | |
8677 | 2553 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2554 ws[0] = '\0'; |
2555 wpos = 0; | |
8177 | 2556 /* NEW_BIT (NEW_TEXT_BIT); */ |
9621 | 2557 } else { |
2558 /* A newline is defined by HTML as whitespace, which means we have to replace it with a word boundary. | |
2559 * word breaks vary depending on the language used, so the correct thing to do is to use Pango to determine | |
2560 * what language this is, determine the proper word boundary to use, and insert that. I'm just going to insert | |
2561 * a space instead. What are the non-English speakers going to do? Complain in a language I'll understand? | |
2562 * Bu-wahaha! */ | |
2563 ws[wpos] = ' '; | |
2564 wpos++; | |
2565 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
2566 ws[0] = '\0'; | |
2567 wpos = 0; | |
1428 | 2568 } |
2569 c++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2570 pos++; |
8334 | 2571 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){ |
2572 while(len_protocol--){ | |
8677 | 2573 /* Skip the next len_protocol characters, but make sure they're |
8334 | 2574 copied into the ws array. |
2575 */ | |
2576 ws [wpos++] = *c++; | |
2577 pos++; | |
2578 } | |
8061 | 2579 } else if (*c) { |
1428 | 2580 ws [wpos++] = *c++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2581 pos++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2582 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2583 break; |
1428 | 2584 } |
2585 } | |
8677 | 2586 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2587 ws[0] = '\0'; wpos = 0; |
2588 | |
8177 | 2589 /* NEW_BIT(NEW_TEXT_BIT); */ |
8061 | 2590 |
4032 | 2591 while (fonts) { |
5967 | 2592 GtkIMHtmlFontDetail *font = fonts->data; |
4032 | 2593 fonts = g_slist_remove (fonts, font); |
2594 if (font->face) | |
2595 g_free (font->face); | |
2596 if (font->fore) | |
2597 g_free (font->fore); | |
2598 if (font->back) | |
2599 g_free (font->back); | |
2600 if (font->sml) | |
2601 g_free (font->sml); | |
2602 g_free (font); | |
2603 } | |
8932 | 2604 |
2605 g_free(ws); | |
2606 if (bg) | |
4630 | 2607 g_free(bg); |
8677 | 2608 |
2609 if (!imhtml->wbfo) | |
8698 | 2610 gtk_imhtml_close_tags(imhtml, iter); |
8506 | 2611 |
2612 object = g_object_ref(G_OBJECT(imhtml)); | |
2613 g_signal_emit(object, signals[UPDATE_FORMAT], 0); | |
2614 g_object_unref(object); | |
2615 | |
3922 | 2616 } |
2617 | |
4892 | 2618 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
2619 { | |
4288 | 2620 g_hash_table_destroy(imhtml->smiley_data); |
2621 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
4892 | 2622 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 2623 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4288 | 2624 imhtml->default_smilies = gtk_smiley_tree_new(); |
2625 } | |
8481 | 2626 |
3922 | 2627 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, |
4253 | 2628 gboolean show) |
2629 { | |
6124 | 2630 imhtml->show_comments = show; |
4253 | 2631 } |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2632 |
8456 | 2633 void gtk_imhtml_html_shortcuts (GtkIMHtml *imhtml, |
2634 gboolean allow) | |
2635 { | |
2636 imhtml->html_shortcuts = allow; | |
2637 } | |
2638 | |
2639 void gtk_imhtml_smiley_shortcuts (GtkIMHtml *imhtml, | |
2640 gboolean allow) | |
2641 { | |
2642 imhtml->smiley_shortcuts = allow; | |
2643 } | |
2644 | |
8962 | 2645 void |
9029 | 2646 gtk_imhtml_set_protocol_name(GtkIMHtml *imhtml, const gchar *protocol_name) { |
2647 if (imhtml->protocol_name) | |
2648 g_free(imhtml->protocol_name); | |
2649 imhtml->protocol_name = protocol_name ? g_strdup(protocol_name) : NULL; | |
8456 | 2650 } |
2651 | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2652 void |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2653 gtk_imhtml_clear (GtkIMHtml *imhtml) |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2654 { |
7991 | 2655 GList *del; |
3922 | 2656 GtkTextIter start, end; |
8427 | 2657 GObject *object = g_object_ref(G_OBJECT(imhtml)); |
7991 | 2658 |
3922 | 2659 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2660 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2661 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
7991 | 2662 |
2663 for(del = imhtml->scalables; del; del = del->next) { | |
2664 GtkIMHtmlScalable *scale = del->data; | |
2665 scale->free(scale); | |
2666 } | |
2667 g_list_free(imhtml->scalables); | |
2668 imhtml->scalables = NULL; | |
8061 | 2669 |
8719 | 2670 gtk_imhtml_close_tags(imhtml, &start); |
8481 | 2671 |
8427 | 2672 g_signal_emit(object, signals[CLEAR_FORMAT], 0); |
2673 g_object_unref(object); | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2674 } |
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
2675 |
4046 | 2676 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
2677 { | |
5282 | 2678 GdkRectangle rect; |
2679 GtkTextIter iter; | |
4046 | 2680 |
5282 | 2681 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
2682 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2683 rect.y - rect.height); | |
2684 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
8061 | 2685 |
4046 | 2686 } |
5282 | 2687 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
2688 { | |
2689 GdkRectangle rect; | |
2690 GtkTextIter iter; | |
2691 | |
2692 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
2693 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2694 rect.y + rect.height); | |
2695 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
2696 } | |
4735 | 2697 |
5967 | 2698 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
8962 | 2699 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id) |
4735 | 2700 { |
5967 | 2701 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
5012 | 2702 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
4895 | 2703 |
5967 | 2704 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
2705 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
2706 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
5046 | 2707 |
2708 im_image->pixbuf = img; | |
5012 | 2709 im_image->image = image; |
4895 | 2710 im_image->width = gdk_pixbuf_get_width(img); |
2711 im_image->height = gdk_pixbuf_get_height(img); | |
2712 im_image->mark = NULL; | |
6982 | 2713 im_image->filename = filename ? g_strdup(filename) : NULL; |
8962 | 2714 im_image->id = id; |
9573 | 2715 im_image->filesel = NULL; |
4895 | 2716 |
5046 | 2717 g_object_ref(img); |
4895 | 2718 return GTK_IMHTML_SCALABLE(im_image); |
2719 } | |
2720 | |
5967 | 2721 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
4895 | 2722 { |
5967 | 2723 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
4895 | 2724 |
2725 if(image->width > width || image->height > height){ | |
2726 GdkPixbuf *new_image = NULL; | |
2727 float factor; | |
2728 int new_width = image->width, new_height = image->height; | |
2729 | |
8588 | 2730 if(image->width > (width - 2)){ |
4895 | 2731 factor = (float)(width)/image->width; |
2732 new_width = width; | |
2733 new_height = image->height * factor; | |
2734 } | |
8588 | 2735 if(new_height >= (height - 2)){ |
4895 | 2736 factor = (float)(height)/new_height; |
2737 new_height = height; | |
2738 new_width = new_width * factor; | |
2739 } | |
2740 | |
5046 | 2741 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
5012 | 2742 gtk_image_set_from_pixbuf(image->image, new_image); |
4895 | 2743 g_object_unref(G_OBJECT(new_image)); |
2744 } | |
2745 } | |
2746 | |
9573 | 2747 static void |
2748 image_save_yes_cb(GtkIMHtmlImage *image, const char *filename) | |
5012 | 2749 { |
2750 gchar *type = NULL; | |
5019 | 2751 GError *error = NULL; |
5015 | 2752 #if GTK_CHECK_VERSION(2,2,0) |
5012 | 2753 GSList *formats = gdk_pixbuf_get_formats(); |
6162 | 2754 #else |
2755 char *basename = g_path_get_basename(filename); | |
2756 char *ext = strrchr(basename, '.'); | |
5959 | 2757 #endif |
5012 | 2758 |
9573 | 2759 gtk_widget_destroy(image->filesel); |
2760 image->filesel = NULL; | |
5959 | 2761 |
2762 #if GTK_CHECK_VERSION(2,2,0) | |
9573 | 2763 while (formats) { |
5012 | 2764 GdkPixbufFormat *format = formats->data; |
2765 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
2766 gpointer p = extensions; | |
2767 | |
2768 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
2769 gchar *fmt_ext = extensions[0]; | |
2770 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
2771 | |
2772 if(!strcmp(fmt_ext, file_ext)){ | |
2773 type = gdk_pixbuf_format_get_name(format); | |
2774 break; | |
2775 } | |
2776 | |
2777 extensions++; | |
2778 } | |
2779 | |
2780 g_strfreev(p); | |
2781 | |
9573 | 2782 if (type) |
5012 | 2783 break; |
2784 | |
2785 formats = formats->next; | |
2786 } | |
2787 | |
5020 | 2788 g_slist_free(formats); |
2789 #else | |
2790 /* this is really ugly code, but I think it will work */ | |
9573 | 2791 if (ext) { |
5020 | 2792 ext++; |
9573 | 2793 if (!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) |
5020 | 2794 type = g_strdup("jpeg"); |
9573 | 2795 else if (!g_ascii_strcasecmp(ext, "png")) |
5020 | 2796 type = g_strdup("png"); |
2797 } | |
2798 | |
2799 g_free(basename); | |
2800 #endif | |
2801 | |
5012 | 2802 /* If I can't find a valid type, I will just tell the user about it and then assume |
2803 it's a png */ | |
9573 | 2804 if (!type){ |
5012 | 2805 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, |
9706 | 2806 _("Unable to guess the image type based on the file extension supplied. Using \".image\"")); |
2807 type = g_strdup("image"); | |
5012 | 2808 } |
2809 | |
5046 | 2810 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
5012 | 2811 |
9573 | 2812 if (error){ |
5012 | 2813 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, |
2814 _("Error saving image: %s"), error->message); | |
2815 g_error_free(error); | |
2816 } | |
2817 | |
2818 g_free(type); | |
2819 } | |
2820 | |
9573 | 2821 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
2822 static void | |
2823 image_save_check_if_exists_cb(GtkWidget *widget, gint response, GtkIMHtmlImage *image) | |
2824 { | |
2825 gchar *filename; | |
2826 | |
2827 if (response != GTK_RESPONSE_ACCEPT) { | |
2828 gtk_widget_destroy(widget); | |
2829 image->filesel = NULL; | |
2830 return; | |
2831 } | |
2832 | |
2833 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); | |
2834 #else /* FILECHOOSER */ | |
2835 static void | |
2836 image_save_check_if_exists_cb(GtkWidget *button, GtkIMHtmlImage *image) | |
5012 | 2837 { |
9573 | 2838 gchar *filename; |
2839 | |
2840 filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(image->filesel))); | |
2841 | |
2842 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { | |
2843 gchar *dirname; | |
2844 /* append a / is needed */ | |
2845 if (filename[strlen(filename) - 1] != G_DIR_SEPARATOR) { | |
2846 dirname = g_strconcat(filename, G_DIR_SEPARATOR_S, NULL); | |
2847 } else { | |
2848 dirname = g_strdup(filename); | |
2849 } | |
9574 | 2850 gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), dirname); |
9573 | 2851 g_free(dirname); |
2852 g_free(filename); | |
2853 return; | |
2854 } | |
2855 #endif /* FILECHOOSER */ | |
2856 | |
2857 /* | |
2858 * XXX - We should probably prompt the user to determine if they really | |
2859 * want to overwrite the file or not. However, I don't feel like doing | |
2860 * that, so we're just always going to overwrite if the file exists. | |
2861 */ | |
2862 /* | |
2863 if (g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
2864 } else | |
2865 image_save_yes_cb(image, filename); | |
2866 */ | |
2867 | |
2868 image_save_yes_cb(image, filename); | |
2869 | |
2870 g_free(filename); | |
2871 } | |
2872 | |
2873 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ | |
2874 static void | |
2875 image_save_cancel_cb(GtkIMHtmlImage *image) | |
2876 { | |
2877 gtk_widget_destroy(image->filesel); | |
2878 image->filesel = NULL; | |
2879 } | |
2880 #endif /* FILECHOOSER */ | |
2881 | |
2882 static void | |
2883 gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) | |
2884 { | |
2885 if (image->filesel != NULL) { | |
2886 gtk_window_present(GTK_WINDOW(image->filesel)); | |
2887 return; | |
2888 } | |
2889 | |
2890 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ | |
2891 image->filesel = gtk_file_chooser_dialog_new(_("Save Image"), | |
2892 NULL, | |
2893 GTK_FILE_CHOOSER_ACTION_SAVE, | |
2894 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
2895 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, | |
2896 NULL); | |
2897 gtk_dialog_set_default_response(GTK_DIALOG(image->filesel), GTK_RESPONSE_ACCEPT); | |
2898 if (image->filename != NULL) | |
2899 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(image->filesel), image->filename); | |
2900 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(image->filesel)), "response", | |
2901 G_CALLBACK(image_save_check_if_exists_cb), image); | |
2902 #else /* FILECHOOSER */ | |
2903 image->filesel = gtk_file_selection_new(_("Save Image")); | |
2904 if (image->filename != NULL) | |
2905 gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), image->filename); | |
9574 | 2906 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)), "delete_event", |
2907 G_CALLBACK(image_save_cancel_cb), image); | |
2908 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->cancel_button), | |
2909 "clicked", G_CALLBACK(image_save_cancel_cb), image); | |
9573 | 2910 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->ok_button), "clicked", |
2911 G_CALLBACK(image_save_check_if_exists_cb), image); | |
2912 #endif /* FILECHOOSER */ | |
2913 | |
2914 gtk_widget_show(image->filesel); | |
5012 | 2915 } |
2916 | |
5967 | 2917 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
5012 | 2918 { |
2919 GdkEventButton *event_button = (GdkEventButton *) event; | |
2920 | |
2921 if (event->type == GDK_BUTTON_RELEASE) { | |
2922 if(event_button->button == 3) { | |
2923 GtkWidget *img, *item, *menu; | |
2924 gchar *text = g_strdup_printf(_("_Save Image...")); | |
2925 menu = gtk_menu_new(); | |
2926 | |
2927 /* buttons and such */ | |
2928 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
2929 item = gtk_image_menu_item_new_with_mnemonic(text); | |
2930 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
5967 | 2931 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
5012 | 2932 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
2933 | |
2934 gtk_widget_show_all(menu); | |
2935 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
2936 event_button->button, event_button->time); | |
2937 | |
2938 g_free(text); | |
2939 return TRUE; | |
2940 } | |
2941 } | |
2942 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
2943 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
2944 be caught by the regular GtkTextView menu */ | |
2945 else | |
2946 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
2947 | |
2948 } | |
5967 | 2949 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
2950 { | |
2951 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2952 | |
2953 g_object_unref(image->pixbuf); | |
6982 | 2954 if (image->filename) |
2955 g_free(image->filename); | |
9573 | 2956 if (image->filesel) |
2957 gtk_widget_destroy(image->filesel); | |
5967 | 2958 g_free(scale); |
2959 } | |
2960 | |
2961 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2962 { | |
2963 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2964 GtkWidget *box = gtk_event_box_new(); | |
8962 | 2965 char *tag; |
5967 | 2966 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
2967 | |
2968 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
9229 | 2969 |
2970 if(!gtk_check_version(2, 4, 0)) | |
2971 g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL); | |
5967 | 2972 |
2973 gtk_widget_show(GTK_WIDGET(image->image)); | |
2974 gtk_widget_show(box); | |
2975 | |
8962 | 2976 tag = g_strdup_printf("<IMG ID=\"%d\">", image->id); |
2977 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", tag, g_free); | |
2978 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "[Image]"); | |
2979 | |
5967 | 2980 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); |
2981 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
2982 } | |
2983 | |
2984 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
2985 { | |
2986 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
2987 | |
2988 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
2989 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
2990 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
2991 | |
2992 hr->sep = gtk_hseparator_new(); | |
2993 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
2994 gtk_widget_show(hr->sep); | |
2995 | |
2996 return GTK_IMHTML_SCALABLE(hr); | |
2997 } | |
2998 | |
2999 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
3000 { | |
8588 | 3001 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width - 2, 2); |
5967 | 3002 } |
3003 | |
3004 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
3005 { | |
3006 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
3007 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
8698 | 3008 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_htmltext", "<hr>"); |
3009 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "\n---\n"); | |
5967 | 3010 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); |
3011 } | |
3012 | |
3013 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
3014 { | |
3015 g_free(scale); | |
3016 } | |
7295 | 3017 |
3018 gboolean gtk_imhtml_search_find(GtkIMHtml *imhtml, const gchar *text) | |
3019 { | |
3020 GtkTextIter iter, start, end; | |
3021 gboolean new_search = TRUE; | |
3022 | |
3023 g_return_val_if_fail(imhtml != NULL, FALSE); | |
3024 g_return_val_if_fail(text != NULL, FALSE); | |
8061 | 3025 |
7295 | 3026 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) |
3027 new_search = FALSE; | |
8061 | 3028 |
7295 | 3029 if (new_search) { |
3030 gtk_imhtml_search_clear(imhtml); | |
3031 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
3032 } else { | |
3033 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, | |
8061 | 3034 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); |
7295 | 3035 } |
3036 imhtml->search_string = g_strdup(text); | |
3037 | |
7358 | 3038 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, |
3039 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
7295 | 3040 &start, &end, NULL)) { |
3041 | |
3042 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); | |
3043 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); | |
3044 if (new_search) { | |
3045 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); | |
8061 | 3046 do |
7295 | 3047 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); |
8061 | 3048 while (gtk_source_iter_forward_search(&end, imhtml->search_string, |
3049 GTK_SOURCE_SEARCH_VISIBLE_ONLY | | |
7358 | 3050 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, |
7295 | 3051 &start, &end, NULL)); |
3052 } | |
3053 return TRUE; | |
3054 } | |
8061 | 3055 |
3056 gtk_imhtml_search_clear(imhtml); | |
3057 | |
7295 | 3058 return FALSE; |
3059 } | |
3060 | |
3061 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) | |
3062 { | |
3063 GtkTextIter start, end; | |
8061 | 3064 |
7295 | 3065 g_return_if_fail(imhtml != NULL); |
8061 | 3066 |
7295 | 3067 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
3068 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
3069 | |
3070 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
3071 if (imhtml->search_string) | |
3072 g_free(imhtml->search_string); | |
3073 imhtml->search_string = NULL; | |
3074 } | |
8061 | 3075 |
8677 | 3076 static GtkTextTag *find_font_forecolor_tag(GtkIMHtml *imhtml, gchar *color) |
3077 { | |
3078 gchar str[18]; | |
3079 GtkTextTag *tag; | |
3080 | |
3081 g_snprintf(str, sizeof(str), "FORECOLOR %s", color); | |
3082 | |
3083 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3084 if (!tag) | |
3085 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", color, NULL); | |
3086 | |
3087 return tag; | |
3088 } | |
3089 | |
3090 static GtkTextTag *find_font_backcolor_tag(GtkIMHtml *imhtml, gchar *color) | |
3091 { | |
3092 gchar str[18]; | |
3093 GtkTextTag *tag; | |
3094 | |
3095 g_snprintf(str, sizeof(str), "BACKCOLOR %s", color); | |
3096 | |
3097 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3098 if (!tag) | |
3099 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "background", color, NULL); | |
3100 | |
3101 return tag; | |
3102 } | |
3103 | |
3104 static GtkTextTag *find_font_face_tag(GtkIMHtml *imhtml, gchar *face) | |
8061 | 3105 { |
8677 | 3106 gchar str[256]; |
3107 GtkTextTag *tag; | |
3108 | |
3109 g_snprintf(str, sizeof(str), "FONT FACE %s", face); | |
3110 str[255] = '\0'; | |
3111 | |
3112 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3113 if (!tag) | |
3114 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "family", face, NULL); | |
3115 | |
3116 return tag; | |
3117 } | |
3118 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3119 static void _init_original_fsize(GtkIMHtml *imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3120 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3121 GtkTextAttributes *attr; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3122 attr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3123 imhtml->original_fsize = pango_font_description_get_size(attr->font); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3124 gtk_text_attributes_unref(attr); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3125 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3126 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3127 static void _recalculate_font_sizes(GtkTextTag *tag, gpointer imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3128 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3129 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3130 int size; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3131 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3132 size = strtol(tag->name + 10, NULL, 10); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3133 g_object_set(G_OBJECT(tag), "size", |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3134 (gint) (GTK_IMHTML(imhtml)->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3135 ((double) _point_sizes[size-1] * GTK_IMHTML(imhtml)->zoom)), NULL); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3136 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3137 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3138 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3139 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3140 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3141 void gtk_imhtml_font_zoom(GtkIMHtml *imhtml, double zoom) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3142 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3143 GtkRcStyle *s; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3144 PangoFontDescription *font_desc = pango_font_description_new(); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3145 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3146 imhtml->zoom = zoom; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3147 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3148 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3149 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3150 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3151 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
|
3152 _recalculate_font_sizes, imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3153 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3154 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
|
3155 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3156 s = gtk_widget_get_modifier_style(GTK_WIDGET(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3157 s->font_desc = font_desc; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3158 gtk_widget_modify_style(GTK_WIDGET(imhtml), s); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3159 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3160 |
8677 | 3161 static GtkTextTag *find_font_size_tag(GtkIMHtml *imhtml, int size) |
3162 { | |
3163 gchar str[24]; | |
3164 GtkTextTag *tag; | |
3165 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3166 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3167 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3168 |
8677 | 3169 g_snprintf(str, sizeof(str), "FONT SIZE %d", size); |
3170 str[23] = '\0'; | |
3171 | |
3172 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3173 if (!tag) { | |
3174 /* For reasons I don't understand, setting "scale" here scaled based on some default | |
3175 * size other than my theme's default size. Our size 4 was actually smaller than | |
3176 * our size 3 for me. So this works around that oddity. | |
3177 */ | |
3178 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
|
3179 (gint) (imhtml->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3180 ((double) _point_sizes[size-1] * imhtml->zoom)), NULL); |
8061 | 3181 } |
3182 | |
8677 | 3183 return tag; |
3184 } | |
3185 | |
3186 static void remove_tag_by_prefix(GtkIMHtml *imhtml, const GtkTextIter *i, const GtkTextIter *e, | |
3187 const char *prefix, guint len, gboolean homo) | |
3188 { | |
3189 GSList *tags, *l; | |
3190 GtkTextIter iter; | |
3191 | |
3192 tags = gtk_text_iter_get_tags(i); | |
3193 | |
3194 for (l = tags; l; l = l->next) { | |
3195 GtkTextTag *tag = l->data; | |
3196 | |
3197 if (tag->name && !strncmp(tag->name, prefix, len)) | |
3198 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, i, e); | |
8061 | 3199 } |
3200 | |
8677 | 3201 g_slist_free(tags); |
3202 | |
3203 if (homo) | |
3204 return; | |
3205 | |
3206 iter = *i; | |
3207 | |
3208 while (gtk_text_iter_forward_char(&iter) && !gtk_text_iter_equal(&iter, e)) { | |
3209 if (gtk_text_iter_begins_tag(&iter, NULL)) { | |
3210 tags = gtk_text_iter_get_toggled_tags(&iter, TRUE); | |
3211 | |
3212 for (l = tags; l; l = l->next) { | |
3213 GtkTextTag *tag = l->data; | |
3214 | |
3215 if (tag->name && !strncmp(tag->name, prefix, len)) | |
3216 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, &iter, e); | |
3217 } | |
3218 | |
3219 g_slist_free(tags); | |
3220 } | |
8061 | 3221 } |
8677 | 3222 } |
3223 | |
3224 static void remove_font_size(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3225 { | |
3226 remove_tag_by_prefix(imhtml, i, e, "FONT SIZE ", 10, homo); | |
3227 } | |
3228 | |
3229 static void remove_font_face(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3230 { | |
3231 remove_tag_by_prefix(imhtml, i, e, "FONT FACE ", 10, homo); | |
3232 } | |
3233 | |
3234 static void remove_font_forecolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3235 { | |
3236 remove_tag_by_prefix(imhtml, i, e, "FORECOLOR ", 10, homo); | |
3237 } | |
3238 | |
3239 static void remove_font_backcolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3240 { | |
3241 remove_tag_by_prefix(imhtml, i, e, "BACKCOLOR ", 10, homo); | |
3242 } | |
3243 | |
3244 static void remove_font_link(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3245 { | |
3246 remove_tag_by_prefix(imhtml, i, e, "LINK ", 5, homo); | |
3247 } | |
3248 | |
3249 /* Editable stuff */ | |
3250 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) | |
3251 { | |
3252 imhtml->insert_offset = gtk_text_iter_get_offset(iter); | |
3253 } | |
3254 | |
3255 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *end, gchar *text, gint len, GtkIMHtml *imhtml) | |
3256 { | |
3257 GtkTextIter start; | |
3258 | |
3259 if (!len) | |
3260 return; | |
3261 | |
3262 start = *end; | |
3263 gtk_text_iter_set_offset(&start, imhtml->insert_offset); | |
3264 | |
3265 if (imhtml->edit.bold) | |
3266 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, end); | |
3267 else | |
3268 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, end); | |
3269 | |
3270 if (imhtml->edit.italic) | |
3271 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end); | |
3272 else | |
3273 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end); | |
3274 | |
3275 if (imhtml->edit.underline) | |
3276 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end); | |
3277 else | |
3278 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end); | |
3279 | |
3280 if (imhtml->edit.forecolor) { | |
3281 remove_font_forecolor(imhtml, &start, end, TRUE); | |
3282 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3283 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
3284 &start, end); | |
8061 | 3285 } |
3286 | |
8677 | 3287 if (imhtml->edit.backcolor) { |
3288 remove_font_backcolor(imhtml, &start, end, TRUE); | |
3289 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3290 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), | |
3291 &start, end); | |
3292 } | |
3293 | |
3294 if (imhtml->edit.fontface) { | |
3295 remove_font_face(imhtml, &start, end, TRUE); | |
3296 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3297 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
3298 &start, end); | |
8061 | 3299 } |
8677 | 3300 |
3301 if (imhtml->edit.fontsize) { | |
3302 remove_font_size(imhtml, &start, end, TRUE); | |
3303 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3304 find_font_size_tag(imhtml, imhtml->edit.fontsize), | |
3305 &start, end); | |
3306 } | |
3307 | |
3308 if (imhtml->edit.link) { | |
3309 remove_font_link(imhtml, &start, end, TRUE); | |
3310 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3311 imhtml->edit.link, | |
3312 &start, end); | |
3313 } | |
3314 | |
8061 | 3315 } |
3316 | |
3317 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) | |
3318 { | |
3319 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); | |
8177 | 3320 /* |
3321 * We need a visible caret for accessibility, so mouseless | |
3322 * people can highlight stuff. | |
3323 */ | |
3324 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */ | |
8061 | 3325 imhtml->editable = editable; |
8677 | 3326 imhtml->format_functions = GTK_IMHTML_ALL; |
3327 | |
3328 if (editable) | |
3329 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set", | |
3330 G_CALLBACK(mark_set_cb), imhtml); | |
3331 } | |
3332 | |
3333 void gtk_imhtml_set_whole_buffer_formatting_only(GtkIMHtml *imhtml, gboolean wbfo) | |
3334 { | |
3335 g_return_if_fail(imhtml != NULL); | |
3336 | |
3337 imhtml->wbfo = wbfo; | |
8420 | 3338 } |
3339 | |
3340 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons) | |
3341 { | |
3342 GObject *object = g_object_ref(G_OBJECT(imhtml)); | |
8677 | 3343 imhtml->format_functions = buttons; |
8420 | 3344 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons); |
3345 g_object_unref(object); | |
8061 | 3346 } |
3347 | |
8788 | 3348 GtkIMHtmlButtons gtk_imhtml_get_format_functions(GtkIMHtml *imhtml) |
3349 { | |
3350 return imhtml->format_functions; | |
3351 } | |
8516 | 3352 |
3353 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold, | |
3354 gboolean *italic, gboolean *underline) | |
8481 | 3355 { |
8677 | 3356 if (imhtml->edit.bold) |
3357 (*bold) = TRUE; | |
3358 if (imhtml->edit.italic) | |
3359 (*italic) = TRUE; | |
3360 if (imhtml->edit.underline) | |
3361 (*underline) = TRUE; | |
8481 | 3362 } |
3363 | |
9025 | 3364 char * |
3365 gtk_imhtml_get_current_fontface(GtkIMHtml *imhtml) | |
3366 { | |
3367 if (imhtml->edit.fontface) | |
3368 return g_strdup(imhtml->edit.fontface); | |
3369 else | |
3370 return NULL; | |
3371 } | |
3372 | |
3373 char * | |
3374 gtk_imhtml_get_current_forecolor(GtkIMHtml *imhtml) | |
3375 { | |
3376 if (imhtml->edit.forecolor) | |
3377 return g_strdup(imhtml->edit.forecolor); | |
3378 else | |
3379 return NULL; | |
3380 } | |
3381 | |
3382 char * | |
3383 gtk_imhtml_get_current_backcolor(GtkIMHtml *imhtml) | |
3384 { | |
3385 if (imhtml->edit.backcolor) | |
3386 return g_strdup(imhtml->edit.backcolor); | |
3387 else | |
3388 return NULL; | |
3389 } | |
3390 | |
3391 gint | |
3392 gtk_imhtml_get_current_fontsize(GtkIMHtml *imhtml) | |
3393 { | |
3394 return imhtml->edit.fontsize; | |
3395 } | |
3396 | |
8061 | 3397 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) |
3398 { | |
3399 return imhtml->editable; | |
3400 } | |
3401 | |
8677 | 3402 /* |
3403 * I had this crazy idea about changing the text cursor color to reflex the foreground color | |
3404 * of the text about to be entered. This is the place you'd do it, along with the place where | |
3405 * we actually set a new foreground color. | |
3406 * I may not do this, because people will bitch about Gaim overriding their gtk theme's cursor | |
3407 * colors. | |
3408 * | |
3409 * Just in case I do do this, I asked about what to set the secondary text cursor to. | |
3410 * | |
8719 | 3411 * (12:45:27) ?? ???: secondary_cursor_color = (rgb(background) + rgb(primary_cursor_color) ) / 2 |
3412 * (12:45:55) ?? ???: understand? | |
8677 | 3413 * (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
|
3414 * (12:46:56) ?? ???: u might need to extract separate each color from RGB |
8677 | 3415 */ |
3416 | |
3417 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, | |
3418 GtkIMHtml *imhtml) | |
3419 { | |
3420 GSList *tags, *l; | |
3421 GtkTextIter iter; | |
3422 | |
3423 if (mark != gtk_text_buffer_get_insert(buffer)) | |
3424 return; | |
3425 | |
3426 if (!gtk_text_buffer_get_char_count(buffer)) | |
3427 return; | |
3428 | |
3429 imhtml->edit.bold = imhtml->edit.italic = imhtml->edit.underline = FALSE; | |
3430 if (imhtml->edit.forecolor) | |
3431 g_free(imhtml->edit.forecolor); | |
3432 imhtml->edit.forecolor = NULL; | |
3433 if (imhtml->edit.backcolor) | |
3434 g_free(imhtml->edit.backcolor); | |
3435 imhtml->edit.backcolor = NULL; | |
3436 if (imhtml->edit.fontface) | |
3437 g_free(imhtml->edit.fontface); | |
3438 imhtml->edit.fontface = NULL; | |
3439 imhtml->edit.fontsize = 0; | |
3440 imhtml->edit.link = NULL; | |
3441 | |
3442 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3443 | |
3444 | |
3445 if (gtk_text_iter_is_end(&iter)) | |
3446 tags = gtk_text_iter_get_toggled_tags(&iter, FALSE); | |
3447 else | |
3448 tags = gtk_text_iter_get_tags(&iter); | |
3449 | |
3450 for (l = tags; l != NULL; l = l->next) { | |
3451 GtkTextTag *tag = GTK_TEXT_TAG(l->data); | |
3452 | |
3453 if (tag->name) { | |
3454 if (strcmp(tag->name, "BOLD") == 0) | |
3455 imhtml->edit.bold = TRUE; | |
3456 if (strcmp(tag->name, "ITALICS") == 0) | |
3457 imhtml->edit.italic = TRUE; | |
3458 if (strcmp(tag->name, "UNDERLINE") == 0) | |
3459 imhtml->edit.underline = TRUE; | |
3460 if (strncmp(tag->name, "FORECOLOR ", 10) == 0) | |
3461 imhtml->edit.forecolor = g_strdup(&(tag->name)[10]); | |
3462 if (strncmp(tag->name, "BACKCOLOR ", 10) == 0) | |
3463 imhtml->edit.backcolor = g_strdup(&(tag->name)[10]); | |
3464 if (strncmp(tag->name, "FONT FACE ", 10) == 0) | |
3465 imhtml->edit.fontface = g_strdup(&(tag->name)[10]); | |
3466 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) | |
3467 imhtml->edit.fontsize = strtol(&(tag->name)[10], NULL, 10); | |
8719 | 3468 if ((strncmp(tag->name, "LINK ", 5) == 0) && !gtk_text_iter_is_end(&iter)) |
8677 | 3469 imhtml->edit.link = tag; |
3470 } | |
3471 } | |
3472 | |
3473 g_slist_free(tags); | |
3474 } | |
3475 | |
8061 | 3476 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) |
3477 { | |
8481 | 3478 GObject *object; |
8677 | 3479 GtkTextIter start, end; |
3480 | |
3481 imhtml->edit.bold = !imhtml->edit.bold; | |
3482 | |
3483 if (imhtml->wbfo) { | |
3484 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3485 if (imhtml->edit.bold) | |
3486 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3487 else | |
3488 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3489 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3490 if (imhtml->edit.bold) | |
3491 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3492 else | |
3493 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3494 | |
8061 | 3495 } |
8481 | 3496 object = g_object_ref(G_OBJECT(imhtml)); |
3497 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BOLD); | |
3498 g_object_unref(object); | |
3499 | |
8677 | 3500 return (imhtml->edit.bold != FALSE); |
8061 | 3501 } |
3502 | |
3503 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) | |
3504 { | |
8481 | 3505 GObject *object; |
8677 | 3506 GtkTextIter start, end; |
3507 | |
3508 imhtml->edit.italic = !imhtml->edit.italic; | |
3509 | |
3510 if (imhtml->wbfo) { | |
3511 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3512 if (imhtml->edit.italic) | |
3513 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3514 else | |
3515 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3516 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3517 if (imhtml->edit.italic) | |
3518 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3519 else | |
3520 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
8061 | 3521 } |
8481 | 3522 object = g_object_ref(G_OBJECT(imhtml)); |
3523 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_ITALIC); | |
3524 g_object_unref(object); | |
3525 | |
8677 | 3526 return imhtml->edit.italic != FALSE; |
8061 | 3527 } |
3528 | |
3529 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) | |
3530 { | |
8481 | 3531 GObject *object; |
8677 | 3532 GtkTextIter start, end; |
3533 | |
3534 imhtml->edit.underline = !imhtml->edit.underline; | |
3535 | |
3536 if (imhtml->wbfo) { | |
3537 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3538 if (imhtml->edit.underline) | |
3539 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3540 else | |
3541 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3542 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3543 if (imhtml->edit.underline) | |
3544 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3545 else | |
3546 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
8061 | 3547 } |
8481 | 3548 object = g_object_ref(G_OBJECT(imhtml)); |
3549 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_UNDERLINE); | |
3550 g_object_unref(object); | |
3551 | |
8677 | 3552 return imhtml->edit.underline != FALSE; |
8061 | 3553 } |
3554 | |
3555 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) | |
3556 { | |
9025 | 3557 GObject *object; |
8677 | 3558 GtkTextIter start, end; |
9025 | 3559 GtkIMHtmlButtons b = 0; |
8061 | 3560 |
3561 imhtml->edit.fontsize = size; | |
3562 | |
8677 | 3563 |
3564 if (imhtml->wbfo) { | |
3565 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3566 remove_font_size(imhtml, &start, &end, TRUE); | |
3567 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3568 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3569 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3570 remove_font_size(imhtml, &start, &end, FALSE); | |
3571 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3572 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3573 } |
8677 | 3574 |
9025 | 3575 object = g_object_ref(G_OBJECT(imhtml)); |
3576 b |= GTK_IMHTML_SHRINK; | |
3577 b |= GTK_IMHTML_GROW; | |
3578 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, b); | |
3579 g_object_unref(object); | |
8061 | 3580 } |
3581 | |
3582 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) | |
3583 { | |
9025 | 3584 GObject *object; |
8677 | 3585 GtkTextIter start, end; |
3586 | |
8061 | 3587 if (imhtml->edit.fontsize == 1) |
3588 return; | |
3589 | |
8677 | 3590 if (!imhtml->edit.fontsize) |
3591 imhtml->edit.fontsize = 2; | |
3592 else | |
3593 imhtml->edit.fontsize--; | |
3594 | |
3595 if (imhtml->wbfo) { | |
3596 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3597 remove_font_size(imhtml, &start, &end, TRUE); | |
3598 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3599 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3600 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3601 remove_font_size(imhtml, &start, &end, FALSE); | |
3602 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3603 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3604 } |
9025 | 3605 object = g_object_ref(G_OBJECT(imhtml)); |
3606 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_SHRINK); | |
3607 g_object_unref(object); | |
8061 | 3608 } |
3609 | |
3610 void gtk_imhtml_font_grow(GtkIMHtml *imhtml) | |
3611 { | |
9025 | 3612 GObject *object; |
8677 | 3613 GtkTextIter start, end; |
3614 | |
8061 | 3615 if (imhtml->edit.fontsize == MAX_FONT_SIZE) |
3616 return; | |
3617 | |
8677 | 3618 if (!imhtml->edit.fontsize) |
3619 imhtml->edit.fontsize = 4; | |
3620 else | |
3621 imhtml->edit.fontsize++; | |
3622 | |
3623 if (imhtml->wbfo) { | |
3624 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3625 remove_font_size(imhtml, &start, &end, TRUE); | |
3626 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3627 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3628 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3629 remove_font_size(imhtml, &start, &end, FALSE); | |
3630 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3631 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3632 } |
9025 | 3633 object = g_object_ref(G_OBJECT(imhtml)); |
3634 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_GROW); | |
3635 g_object_unref(object); | |
8061 | 3636 } |
3637 | |
3638 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) | |
3639 { | |
9025 | 3640 GObject *object; |
8677 | 3641 GtkTextIter start, end; |
3642 | |
3643 if (imhtml->edit.forecolor != NULL) | |
3644 g_free(imhtml->edit.forecolor); | |
3645 | |
9025 | 3646 if (color && strcmp(color, "") != 0) { |
8677 | 3647 imhtml->edit.forecolor = g_strdup(color); |
3648 if (imhtml->wbfo) { | |
3649 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3650 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
3651 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3652 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), &start, &end); | |
3653 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3654 remove_font_forecolor(imhtml, &start, &end, FALSE); | |
3655 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3656 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
3657 &start, &end); | |
3658 } | |
8061 | 3659 } else { |
3660 imhtml->edit.forecolor = NULL; | |
9025 | 3661 if (imhtml->wbfo) { |
3662 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3663 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
3664 } | |
8061 | 3665 } |
3666 | |
9025 | 3667 object = g_object_ref(G_OBJECT(imhtml)); |
3668 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_FORECOLOR); | |
3669 g_object_unref(object); | |
3670 | |
8061 | 3671 return imhtml->edit.forecolor != NULL; |
3672 } | |
3673 | |
3674 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) | |
3675 { | |
9025 | 3676 GObject *object; |
8677 | 3677 GtkTextIter start, end; |
3678 | |
3679 if (imhtml->edit.backcolor != NULL) | |
3680 g_free(imhtml->edit.backcolor); | |
3681 | |
9025 | 3682 if (color && strcmp(color, "") != 0) { |
8677 | 3683 imhtml->edit.backcolor = g_strdup(color); |
3684 | |
3685 if (imhtml->wbfo) { | |
3686 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3687 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
3688 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3689 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), &start, &end); | |
3690 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3691 remove_font_backcolor(imhtml, &start, &end, FALSE); | |
3692 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3693 find_font_backcolor_tag(imhtml, | |
3694 imhtml->edit.backcolor), &start, &end); | |
3695 } | |
8061 | 3696 } else { |
3697 imhtml->edit.backcolor = NULL; | |
9025 | 3698 if (imhtml->wbfo) { |
3699 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3700 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
3701 } | |
8061 | 3702 } |
8677 | 3703 |
9025 | 3704 object = g_object_ref(G_OBJECT(imhtml)); |
3705 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BACKCOLOR); | |
3706 g_object_unref(object); | |
3707 | |
8061 | 3708 return imhtml->edit.backcolor != NULL; |
3709 } | |
3710 | |
3711 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) | |
3712 { | |
9025 | 3713 GObject *object; |
8677 | 3714 GtkTextIter start, end; |
3715 | |
3716 if (imhtml->edit.fontface != NULL) | |
3717 g_free(imhtml->edit.fontface); | |
3718 | |
9025 | 3719 if (face && strcmp(face, "") != 0) { |
8677 | 3720 imhtml->edit.fontface = g_strdup(face); |
3721 | |
3722 if (imhtml->wbfo) { | |
3723 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3724 remove_font_face(imhtml, &start, &end, TRUE); | |
3725 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3726 find_font_face_tag(imhtml, imhtml->edit.fontface), &start, &end); | |
3727 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3728 remove_font_face(imhtml, &start, &end, FALSE); | |
3729 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3730 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
3731 &start, &end); | |
3732 } | |
8061 | 3733 } else { |
3734 imhtml->edit.fontface = NULL; | |
9025 | 3735 if (imhtml->wbfo) { |
3736 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3737 remove_font_face(imhtml, &start, &end, TRUE); | |
3738 } | |
8061 | 3739 } |
8677 | 3740 |
9025 | 3741 object = g_object_ref(G_OBJECT(imhtml)); |
3742 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_FACE); | |
3743 g_object_unref(object); | |
3744 | |
8061 | 3745 return imhtml->edit.fontface != NULL; |
3746 } | |
3747 | |
8677 | 3748 void gtk_imhtml_toggle_link(GtkIMHtml *imhtml, const char *url) |
8061 | 3749 { |
9025 | 3750 GObject *object; |
8677 | 3751 GtkTextIter start, end; |
3752 GtkTextTag *linktag; | |
3753 static guint linkno = 0; | |
3754 gchar str[48]; | |
9007 | 3755 GdkColor *color = NULL; |
8677 | 3756 |
3757 imhtml->edit.link = NULL; | |
3758 | |
3759 | |
3760 | |
3761 if (url) { | |
3762 g_snprintf(str, sizeof(str), "LINK %d", linkno++); | |
3763 str[47] = '\0'; | |
3764 | |
9007 | 3765 gtk_widget_style_get(GTK_WIDGET(imhtml), "hyperlink-color", &color, NULL); |
9008 | 3766 if (color) { |
9007 | 3767 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground-gdk", color, "underline", PANGO_UNDERLINE_SINGLE, NULL); |
9008 | 3768 gdk_color_free(color); |
3769 } else { | |
9007 | 3770 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); |
9008 | 3771 } |
8677 | 3772 g_object_set_data_full(G_OBJECT(linktag), "link_url", g_strdup(url), g_free); |
3773 g_signal_connect(G_OBJECT(linktag), "event", G_CALLBACK(tag_event), NULL); | |
3774 | |
3775 if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3776 remove_font_link(imhtml, &start, &end, FALSE); | |
3777 gtk_text_buffer_apply_tag(imhtml->text_buffer, linktag, &start, &end); | |
3778 } | |
3779 } | |
9025 | 3780 |
3781 object = g_object_ref(G_OBJECT(imhtml)); | |
3782 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_LINK); | |
3783 g_object_unref(object); | |
8677 | 3784 } |
3785 | |
3786 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, GtkTextMark *mark, const char *url, const char *text) | |
3787 { | |
8061 | 3788 GtkTextIter iter; |
8677 | 3789 |
9599 | 3790 if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) |
3791 gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE); | |
3792 | |
8677 | 3793 gtk_imhtml_toggle_link(imhtml, url); |
8061 | 3794 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); |
8677 | 3795 gtk_text_buffer_insert(imhtml->text_buffer, &iter, text, -1); |
3796 gtk_imhtml_toggle_link(imhtml, NULL); | |
8061 | 3797 } |
3798 | |
3799 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley) | |
3800 { | |
8677 | 3801 GtkTextMark *mark; |
8061 | 3802 GtkTextIter iter; |
8677 | 3803 |
3804 mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
3805 | |
3806 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3807 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, smiley, &iter); | |
3808 } | |
3809 | |
3810 void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *smiley, GtkTextIter *iter) | |
3811 { | |
8061 | 3812 GdkPixbuf *pixbuf = NULL; |
3813 GdkPixbufAnimation *annipixbuf = NULL; | |
3814 GtkWidget *icon = NULL; | |
3815 GtkTextChildAnchor *anchor; | |
8505 | 3816 char *unescaped = gaim_unescape_html(smiley); |
8061 | 3817 |
8505 | 3818 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); |
8061 | 3819 if(annipixbuf) { |
3820 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
3821 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
3822 if(pixbuf) | |
3823 icon = gtk_image_new_from_pixbuf(pixbuf); | |
3824 } else { | |
3825 icon = gtk_image_new_from_animation(annipixbuf); | |
3826 } | |
3827 } | |
3828 | |
3829 if (icon) { | |
8890 | 3830 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
3831 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", g_strdup(unescaped), g_free); | |
3832 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free); | |
3833 | |
8061 | 3834 gtk_widget_show(icon); |
3835 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); | |
8890 | 3836 } else { |
3837 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, -1); | |
8061 | 3838 } |
8890 | 3839 |
3840 g_free(unescaped); | |
8061 | 3841 } |
3842 | |
8962 | 3843 void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *iter) |
3844 { | |
3845 GdkPixbuf *pixbuf = NULL; | |
3846 const char *filename = NULL; | |
3847 gpointer image; | |
3848 GdkRectangle rect; | |
3849 GtkIMHtmlScalable *scalable = NULL; | |
3850 int minus; | |
3851 | |
3852 if (!imhtml->funcs || !imhtml->funcs->image_get || | |
3853 !imhtml->funcs->image_get_size || !imhtml->funcs->image_get_data || | |
3854 !imhtml->funcs->image_get_filename || !imhtml->funcs->image_ref || | |
3855 !imhtml->funcs->image_unref) | |
3856 return; | |
3857 | |
3858 image = imhtml->funcs->image_get(id); | |
3859 | |
3860 if (image) { | |
3861 gpointer data; | |
3862 size_t len; | |
3863 | |
3864 data = imhtml->funcs->image_get_data(image); | |
3865 len = imhtml->funcs->image_get_size(image); | |
3866 | |
3867 if (data && len) { | |
3868 GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); | |
3869 gdk_pixbuf_loader_write(loader, data, len, NULL); | |
3870 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); | |
9337 | 3871 if (pixbuf) |
3872 g_object_ref(G_OBJECT(pixbuf)); | |
8962 | 3873 gdk_pixbuf_loader_close(loader, NULL); |
9337 | 3874 g_object_unref(G_OBJECT(loader)); |
8962 | 3875 } |
3876 | |
3877 } | |
3878 | |
3879 if (pixbuf) { | |
3880 filename = imhtml->funcs->image_get_filename(image); | |
3881 imhtml->funcs->image_ref(id); | |
3882 imhtml->im_images = g_slist_prepend(imhtml->im_images, GINT_TO_POINTER(id)); | |
3883 } else { | |
3884 pixbuf = gtk_widget_render_icon(GTK_WIDGET(imhtml), GTK_STOCK_MISSING_IMAGE, | |
3885 GTK_ICON_SIZE_BUTTON, "gtkimhtml-missing-image"); | |
3886 } | |
3887 | |
3888 scalable = gtk_imhtml_image_new(pixbuf, filename, id); | |
3889 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
3890 scalable->add_to(scalable, imhtml, iter); | |
3891 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + | |
3892 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
3893 scalable->scale(scalable, rect.width - minus, rect.height); | |
3894 imhtml->scalables = g_list_append(imhtml->scalables, scalable); | |
3895 | |
3896 g_object_unref(G_OBJECT(pixbuf)); | |
3897 } | |
3898 | |
8677 | 3899 static const gchar *tag_to_html_start(GtkTextTag *tag) |
8061 | 3900 { |
8677 | 3901 const gchar *name; |
3902 static gchar buf[1024]; | |
3903 | |
3904 name = tag->name; | |
3905 g_return_val_if_fail(name != NULL, ""); | |
3906 | |
3907 if (strcmp(name, "BOLD") == 0) { | |
3908 return "<b>"; | |
3909 } else if (strcmp(name, "ITALICS") == 0) { | |
3910 return "<i>"; | |
3911 } else if (strcmp(name, "UNDERLINE") == 0) { | |
3912 return "<u>"; | |
3913 } else if (strncmp(name, "LINK ", 5) == 0) { | |
3914 char *tmp = g_object_get_data(G_OBJECT(tag), "link_url"); | |
3915 if (tmp) { | |
3916 g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", tmp); | |
3917 buf[sizeof(buf)-1] = '\0'; | |
3918 return buf; | |
3919 } else { | |
3920 return ""; | |
3921 } | |
3922 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
3923 g_snprintf(buf, sizeof(buf), "<font color=\"%s\">", &name[10]); | |
3924 return buf; | |
3925 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
3926 g_snprintf(buf, sizeof(buf), "<font back=\"%s\">", &name[10]); | |
3927 return buf; | |
3928 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
3929 g_snprintf(buf, sizeof(buf), "<font face=\"%s\">", &name[10]); | |
3930 return buf; | |
3931 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
3932 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]); | |
3933 return buf; | |
3934 } else { | |
3935 return ""; | |
3936 } | |
8061 | 3937 } |
3938 | |
8677 | 3939 static const gchar *tag_to_html_end(GtkTextTag *tag) |
8061 | 3940 { |
8677 | 3941 const gchar *name; |
3942 | |
3943 name = tag->name; | |
3944 g_return_val_if_fail(name != NULL, ""); | |
3945 | |
3946 if (strcmp(name, "BOLD") == 0) { | |
3947 return "</b>"; | |
3948 } else if (strcmp(name, "ITALICS") == 0) { | |
3949 return "</i>"; | |
3950 } else if (strcmp(name, "UNDERLINE") == 0) { | |
3951 return "</u>"; | |
3952 } else if (strncmp(name, "LINK ", 5) == 0) { | |
3953 return "</a>"; | |
3954 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
3955 return "</font>"; | |
3956 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
3957 return "</font>"; | |
3958 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
3959 return "</font>"; | |
3960 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
3961 return "</font>"; | |
3962 } else { | |
3963 return ""; | |
3964 } | |
3965 } | |
3966 | |
3967 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) | |
3968 { | |
3969 return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) && | |
3970 !gtk_text_iter_has_tag(niter, GTK_TEXT_TAG(tag))) || | |
3971 gtk_text_iter_is_end(niter)); | |
8061 | 3972 } |
3973 | |
3974 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such | |
3975 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else | |
8677 | 3976 * check for tags that are toggled on, insert their html form, and push them on the queue. Then insert |
3977 * 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
|
3978 * Finally, replace <, >, &, and " with their HTML equivalent. |
8677 | 3979 */ |
8061 | 3980 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) |
3981 { | |
3982 gunichar c; | |
8677 | 3983 GtkTextIter iter, nextiter; |
8061 | 3984 GString *str = g_string_new(""); |
8677 | 3985 GSList *tags, *sl; |
3986 GQueue *q, *r; | |
3987 GtkTextTag *tag; | |
3988 | |
3989 q = g_queue_new(); | |
3990 r = g_queue_new(); | |
3991 | |
8061 | 3992 |
3993 gtk_text_iter_order(start, end); | |
8677 | 3994 nextiter = iter = *start; |
3995 gtk_text_iter_forward_char(&nextiter); | |
3996 | |
9071 | 3997 /* First add the tags that are already in progress (we don't care about non-printing tags)*/ |
8677 | 3998 tags = gtk_text_iter_get_tags(start); |
3999 | |
4000 for (sl = tags; sl; sl = sl->next) { | |
4001 tag = sl->data; | |
4002 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { | |
9071 | 4003 if (strlen(tag_to_html_end(tag)) > 0) |
4004 g_string_append(str, tag_to_html_start(tag)); | |
8677 | 4005 g_queue_push_tail(q, tag); |
8061 | 4006 } |
4007 } | |
8677 | 4008 g_slist_free(tags); |
8061 | 4009 |
4010 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) { | |
8677 | 4011 |
4012 tags = gtk_text_iter_get_tags(&iter); | |
4013 | |
4014 for (sl = tags; sl; sl = sl->next) { | |
4015 tag = sl->data; | |
4016 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { | |
9071 | 4017 if (strlen(tag_to_html_end(tag)) > 0) |
4018 g_string_append(str, tag_to_html_start(tag)); | |
8677 | 4019 g_queue_push_tail(q, tag); |
4020 } | |
4021 } | |
4022 | |
4023 | |
8061 | 4024 if (c == 0xFFFC) { |
4025 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); | |
9071 | 4026 if (anchor) { |
4027 char *text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext"); | |
4028 if (text) | |
4029 str = g_string_append(str, text); | |
4030 } | |
8677 | 4031 } else if (c == '<') { |
4032 str = g_string_append(str, "<"); | |
4033 } else if (c == '>') { | |
4034 str = g_string_append(str, ">"); | |
4035 } else if (c == '&') { | |
4036 str = g_string_append(str, "&"); | |
4037 } else if (c == '"') { | |
4038 str = g_string_append(str, """); | |
4039 } else if (c == '\n') { | |
4040 str = g_string_append(str, "<br>"); | |
8061 | 4041 } else { |
8677 | 4042 str = g_string_append_unichar(str, c); |
4043 } | |
4044 | |
4045 tags = g_slist_reverse(tags); | |
4046 for (sl = tags; sl; sl = sl->next) { | |
4047 tag = sl->data; | |
9071 | 4048 /** don't worry about non-printing tags ending */ |
4049 if (tag_ends_here(tag, &iter, &nextiter) && strlen(tag_to_html_end(tag)) > 0) { | |
8677 | 4050 |
4051 GtkTextTag *tmp; | |
4052 | |
4053 while ((tmp = g_queue_pop_tail(q)) != tag) { | |
4054 if (tmp == NULL) | |
4055 break; | |
4056 | |
9071 | 4057 if (!tag_ends_here(tmp, &iter, &nextiter) && strlen(tag_to_html_end(tmp)) > 0) |
8677 | 4058 g_queue_push_tail(r, tmp); |
4059 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); | |
4060 } | |
4061 | |
4062 if (tmp == NULL) | |
4063 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); | |
4064 else | |
4065 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
4066 | |
4067 while ((tmp = g_queue_pop_head(r))) { | |
4068 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); | |
4069 g_queue_push_tail(q, tmp); | |
8061 | 4070 } |
4071 } | |
4072 } | |
8677 | 4073 |
4074 g_slist_free(tags); | |
8061 | 4075 gtk_text_iter_forward_char(&iter); |
8677 | 4076 gtk_text_iter_forward_char(&nextiter); |
8061 | 4077 } |
8677 | 4078 |
4079 while ((tag = g_queue_pop_tail(q))) | |
4080 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
4081 | |
4082 g_queue_free(q); | |
4083 g_queue_free(r); | |
8061 | 4084 return g_string_free(str, FALSE); |
4085 } | |
4086 | |
8698 | 4087 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter) |
8061 | 4088 { |
4089 if (imhtml->edit.bold) | |
4090 gtk_imhtml_toggle_bold(imhtml); | |
4091 | |
4092 if (imhtml->edit.italic) | |
4093 gtk_imhtml_toggle_italic(imhtml); | |
4094 | |
4095 if (imhtml->edit.underline) | |
4096 gtk_imhtml_toggle_underline(imhtml); | |
4097 | |
4098 if (imhtml->edit.forecolor) | |
4099 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
4100 | |
4101 if (imhtml->edit.backcolor) | |
4102 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
4103 | |
4104 if (imhtml->edit.fontface) | |
4105 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
4106 | |
8677 | 4107 imhtml->edit.fontsize = 0; |
4108 | |
8719 | 4109 if (imhtml->edit.link) |
4110 gtk_imhtml_toggle_link(imhtml, NULL); | |
4111 | |
8698 | 4112 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter); |
8061 | 4113 |
4114 } | |
4115 | |
4116 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) | |
4117 { | |
4118 GtkTextIter start, end; | |
4119 | |
4120 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
4121 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
4122 return gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
4123 } | |
4124 | |
8677 | 4125 char **gtk_imhtml_get_markup_lines(GtkIMHtml *imhtml) |
4126 { | |
4127 int i, j, lines; | |
4128 GtkTextIter start, end; | |
4129 char **ret; | |
4130 | |
4131 lines = gtk_text_buffer_get_line_count(imhtml->text_buffer); | |
4132 ret = g_new0(char *, lines + 1); | |
4133 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
4134 end = start; | |
4135 gtk_text_iter_forward_to_line_end(&end); | |
4136 | |
4137 for (i = 0, j = 0; i < lines; i++) { | |
9612 | 4138 if (gtk_text_iter_get_char(&start) != '\n') { |
4139 ret[j] = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
4140 if (ret[j] != NULL) | |
4141 j++; | |
4142 } | |
4143 | |
8677 | 4144 gtk_text_iter_forward_line(&start); |
4145 end = start; | |
4146 gtk_text_iter_forward_to_line_end(&end); | |
4147 } | |
4148 | |
4149 return ret; | |
4150 } | |
4151 | |
4152 char *gtk_imhtml_get_text(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *stop) | |
8061 | 4153 { |
8519 | 4154 GString *str = g_string_new(""); |
4155 GtkTextIter iter, end; | |
4156 gunichar c; | |
4157 | |
8677 | 4158 if (start == NULL) |
4159 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
4160 else | |
4161 iter = *start; | |
4162 | |
4163 if (stop == NULL) | |
4164 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
4165 else | |
4166 end = *stop; | |
4167 | |
4168 gtk_text_iter_order(&iter, &end); | |
8519 | 4169 |
4170 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) { | |
4171 if (c == 0xFFFC) { | |
8677 | 4172 GtkTextChildAnchor* anchor; |
4173 char *text = NULL; | |
4174 | |
4175 anchor = gtk_text_iter_get_child_anchor(&iter); | |
4176 if (anchor) | |
8698 | 4177 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext"); |
8677 | 4178 if (text) |
4179 str = g_string_append(str, text); | |
8519 | 4180 } else { |
4181 g_string_append_unichar(str, c); | |
4182 } | |
4183 gtk_text_iter_forward_char(&iter); | |
4184 } | |
4185 | |
4186 return g_string_free(str, FALSE); | |
8061 | 4187 } |
8962 | 4188 |
4189 void gtk_imhtml_set_funcs(GtkIMHtml *imhtml, GtkIMHtmlFuncs *f) | |
4190 { | |
4191 g_return_if_fail(imhtml != NULL); | |
4192 imhtml->funcs = f; | |
4193 } |