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