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