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