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