Mercurial > pidgin
comparison src/gtkimhtml.c @ 5967:156953fe3e14
[gaim-migrate @ 6414]
I gave gtkimhtml some TLC. It no longer contains the word "Gaim," and
it doesn't complain about needing to include a header.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sat, 28 Jun 2003 00:49:56 +0000 |
parents | 5fb6bd688a5b |
children | 460b4ba2d452 |
comparison
equal
deleted
inserted
replaced
5966:5fb6bd688a5b | 5967:156953fe3e14 |
---|---|
56 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD | 56 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD |
57 #endif | 57 #endif |
58 | 58 |
59 #define TOOLTIP_TIMEOUT 500 | 59 #define TOOLTIP_TIMEOUT 500 |
60 | 60 |
61 static gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer user_data); | |
62 static gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer user_data); | |
63 | |
64 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data); | |
65 | |
66 static gboolean gaim_im_image_clicked(GtkWidget *w, GdkEvent *event, gaim_im_image *image); | |
67 | |
68 static gint gtk_imhtml_tip (gpointer data); | |
69 | |
70 | |
71 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a | 61 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
72 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ | 62 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ |
73 #define MAX_FONT_SIZE 7 | 63 #define MAX_FONT_SIZE 7 |
74 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) | 64 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
75 static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 }; | 65 static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 }; |
76 | |
77 /* The four elements present in a <FONT> tag contained in a struct */ | |
78 typedef struct _FontDetail FontDetail; | |
79 struct _FontDetail { | |
80 gushort size; | |
81 gchar *face; | |
82 gchar *fore; | |
83 gchar *back; | |
84 gchar *sml; | |
85 }; | |
86 | |
87 struct _GtkSmileyTree { | |
88 GString *values; | |
89 GtkSmileyTree **children; | |
90 GtkIMHtmlSmiley *image; | |
91 }; | |
92 | 66 |
93 static GtkSmileyTree* | 67 static GtkSmileyTree* |
94 gtk_smiley_tree_new () | 68 gtk_smiley_tree_new () |
95 { | 69 { |
96 return g_new0 (GtkSmileyTree, 1); | 70 return g_new0 (GtkSmileyTree, 1); |
147 } | 121 } |
148 g_free (t); | 122 g_free (t); |
149 } | 123 } |
150 } | 124 } |
151 | 125 |
126 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data) | |
127 { | |
128 GdkRectangle rect; | |
129 | |
130 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect); | |
131 if(widget->old_rect.width != rect.width || widget->old_rect.height != rect.height){ | |
132 GList *iter = GTK_IMHTML(widget)->scalables; | |
133 | |
134 while(iter){ | |
135 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data); | |
136 scale->scale(scale, rect.width, rect.height); | |
137 | |
138 iter = iter->next; | |
139 } | |
140 } | |
141 | |
142 widget->old_rect = rect; | |
143 return FALSE; | |
144 } | |
145 | |
146 static gint | |
147 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
148 { | |
149 PangoLayout *layout; | |
150 | |
151 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
152 | |
153 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
154 | |
155 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, | |
156 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, | |
157 "tooltip", 0, 0, -1, -1); | |
158 | |
159 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
160 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
161 | |
162 g_object_unref(layout); | |
163 return FALSE; | |
164 } | |
165 | |
166 static gint | |
167 gtk_imhtml_tip (gpointer data) | |
168 { | |
169 GtkIMHtml *imhtml = data; | |
170 PangoFontMetrics *font; | |
171 PangoLayout *layout; | |
172 | |
173 gint gap, x, y, h, w, scr_w, baseline_skip; | |
174 | |
175 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
176 | |
177 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
178 imhtml->tip_timer = 0; | |
179 return FALSE; | |
180 } | |
181 | |
182 if (imhtml->tip_window){ | |
183 gtk_widget_destroy (imhtml->tip_window); | |
184 imhtml->tip_window = NULL; | |
185 } | |
186 | |
187 imhtml->tip_timer = 0; | |
188 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
189 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
190 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
191 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
192 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
193 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
194 | |
195 gtk_widget_ensure_style (imhtml->tip_window); | |
196 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
197 font = pango_font_get_metrics(pango_context_load_font(pango_layout_get_context(layout), | |
198 imhtml->tip_window->style->font_desc), | |
199 NULL); | |
200 | |
201 | |
202 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
203 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + | |
204 pango_font_metrics_get_descent(font))/ 4); | |
205 | |
206 if (gap < 2) | |
207 gap = 2; | |
208 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
209 pango_font_metrics_get_descent(font)); | |
210 w = 8 + scr_w; | |
211 h = 8 + baseline_skip; | |
212 | |
213 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
214 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
215 y += GTK_WIDGET(imhtml)->allocation.y; | |
216 | |
217 scr_w = gdk_screen_width(); | |
218 | |
219 x -= ((w >> 1) + 4); | |
220 | |
221 if ((x + w) > scr_w) | |
222 x -= (x + w) - scr_w; | |
223 else if (x < 0) | |
224 x = 0; | |
225 | |
226 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
227 pango_font_metrics_get_descent(font)); | |
228 | |
229 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
230 gtk_widget_show (imhtml->tip_window); | |
231 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
232 | |
233 pango_font_metrics_unref(font); | |
234 g_object_unref(layout); | |
235 | |
236 return FALSE; | |
237 } | |
238 | |
239 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
240 { | |
241 GtkTextIter iter; | |
242 GdkWindow *win = event->window; | |
243 int x, y; | |
244 char *tip = NULL; | |
245 GSList *tags = NULL, *templist = NULL; | |
246 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
247 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
248 event->x, event->y, &x, &y); | |
249 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
250 tags = gtk_text_iter_get_tags(&iter); | |
251 | |
252 templist = tags; | |
253 while (templist) { | |
254 GtkTextTag *tag = templist->data; | |
255 tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
256 if (tip) | |
257 break; | |
258 templist = templist->next; | |
259 } | |
260 | |
261 if (GTK_IMHTML(imhtml)->tip) { | |
262 if ((tip == GTK_IMHTML(imhtml)->tip)) { | |
263 return FALSE; | |
264 } | |
265 /* We've left the cell. Remove the timeout and create a new one below */ | |
266 if (GTK_IMHTML(imhtml)->tip_window) { | |
267 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
268 GTK_IMHTML(imhtml)->tip_window = NULL; | |
269 } | |
270 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
271 if (GTK_IMHTML(imhtml)->tip_timer) | |
272 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
273 GTK_IMHTML(imhtml)->tip_timer = 0; | |
274 } | |
275 | |
276 if(tip){ | |
277 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); | |
278 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, | |
279 gtk_imhtml_tip, imhtml); | |
280 } | |
281 | |
282 GTK_IMHTML(imhtml)->tip = tip; | |
283 g_slist_free(tags); | |
284 return FALSE; | |
285 } | |
286 | |
287 gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer data) | |
288 { | |
289 /* when leaving the widget, clear any current & pending tooltips and restore the cursor */ | |
290 if (GTK_IMHTML(imhtml)->tip_window) { | |
291 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
292 GTK_IMHTML(imhtml)->tip_window = NULL; | |
293 } | |
294 if (GTK_IMHTML(imhtml)->tip_timer) { | |
295 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
296 GTK_IMHTML(imhtml)->tip_timer = 0; | |
297 } | |
298 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
299 | |
300 /* propogate the event normally */ | |
301 return FALSE; | |
302 } | |
303 | |
304 | |
152 | 305 |
153 static GtkTextViewClass *parent_class = NULL; | 306 static GtkTextViewClass *parent_class = NULL; |
154 | |
155 | 307 |
156 /* GtkIMHtml has one signal--URL_CLICKED */ | 308 /* GtkIMHtml has one signal--URL_CLICKED */ |
157 enum { | 309 enum { |
158 URL_CLICKED, | 310 URL_CLICKED, |
159 LAST_SIGNAL | 311 LAST_SIGNAL |
368 be caught by the regular GtkTextView menu */ | 520 be caught by the regular GtkTextView menu */ |
369 else | 521 else |
370 return FALSE; /* Let clicks go through if we didn't catch anything */ | 522 return FALSE; /* Let clicks go through if we didn't catch anything */ |
371 } | 523 } |
372 | 524 |
373 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
374 { | |
375 GtkTextIter iter; | |
376 GdkWindow *win = event->window; | |
377 int x, y; | |
378 char *tip = NULL; | |
379 GSList *tags = NULL, *templist = NULL; | |
380 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
381 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
382 event->x, event->y, &x, &y); | |
383 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
384 tags = gtk_text_iter_get_tags(&iter); | |
385 | |
386 templist = tags; | |
387 while (templist) { | |
388 GtkTextTag *tag = templist->data; | |
389 tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
390 if (tip) | |
391 break; | |
392 templist = templist->next; | |
393 } | |
394 | |
395 if (GTK_IMHTML(imhtml)->tip) { | |
396 if ((tip == GTK_IMHTML(imhtml)->tip)) { | |
397 return FALSE; | |
398 } | |
399 /* We've left the cell. Remove the timeout and create a new one below */ | |
400 if (GTK_IMHTML(imhtml)->tip_window) { | |
401 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
402 GTK_IMHTML(imhtml)->tip_window = NULL; | |
403 } | |
404 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
405 if (GTK_IMHTML(imhtml)->tip_timer) | |
406 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
407 GTK_IMHTML(imhtml)->tip_timer = 0; | |
408 } | |
409 | |
410 if(tip){ | |
411 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); | |
412 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, | |
413 gtk_imhtml_tip, imhtml); | |
414 } | |
415 | |
416 GTK_IMHTML(imhtml)->tip = tip; | |
417 g_slist_free(tags); | |
418 return FALSE; | |
419 } | |
420 | |
421 gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer data) | |
422 { | |
423 /* when leaving the widget, clear any current & pending tooltips and restore the cursor */ | |
424 if (GTK_IMHTML(imhtml)->tip_window) { | |
425 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
426 GTK_IMHTML(imhtml)->tip_window = NULL; | |
427 } | |
428 if (GTK_IMHTML(imhtml)->tip_timer) { | |
429 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
430 GTK_IMHTML(imhtml)->tip_timer = 0; | |
431 } | |
432 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
433 | |
434 /* propogate the event normally */ | |
435 return FALSE; | |
436 } | |
437 | |
438 /* this isn't used yet | 525 /* this isn't used yet |
439 static void | 526 static void |
440 gtk_smiley_tree_remove (GtkSmileyTree *tree, | 527 gtk_smiley_tree_remove (GtkSmileyTree *tree, |
441 GtkIMHtmlSmiley *smiley) | 528 GtkIMHtmlSmiley *smiley) |
442 { | 529 { |
520 GSList *fonts, | 607 GSList *fonts, |
521 const gchar *text, | 608 const gchar *text, |
522 gint *len) | 609 gint *len) |
523 { | 610 { |
524 GtkSmileyTree *tree; | 611 GtkSmileyTree *tree; |
525 FontDetail *font; | 612 GtkIMHtmlFontDetail *font; |
526 char *sml = NULL; | 613 char *sml = NULL; |
527 | 614 |
528 if (fonts) { | 615 if (fonts) { |
529 font = fonts->data; | 616 font = fonts->data; |
530 sml = font->sml; | 617 sml = font->sml; |
835 if (bg) { \ | 922 if (bg) { \ |
836 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \ | 923 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \ |
837 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | 924 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
838 } \ | 925 } \ |
839 if (fonts) { \ | 926 if (fonts) { \ |
840 FontDetail *fd = fonts->data; \ | 927 GtkIMHtmlFontDetail *fd = fonts->data; \ |
841 if (fd->fore) { \ | 928 if (fd->fore) { \ |
842 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \ | 929 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \ |
843 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | 930 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
844 } \ | 931 } \ |
845 if (fd->back) { \ | 932 if (fd->back) { \ |
1038 NEW_BIT (NEW_TEXT_BIT); | 1125 NEW_BIT (NEW_TEXT_BIT); |
1039 break; | 1126 break; |
1040 case 26: /* HR */ | 1127 case 26: /* HR */ |
1041 case 42: /* HR (opt) */ | 1128 case 42: /* HR (opt) */ |
1042 ws[wpos++] = '\n'; | 1129 ws[wpos++] = '\n'; |
1043 scalable = gaim_hr_new(); | 1130 scalable = gtk_imhtml_hr_new(); |
1044 NEW_BIT(NEW_SCALABLE_BIT); | 1131 NEW_BIT(NEW_SCALABLE_BIT); |
1045 ws[wpos++] = '\n'; | 1132 ws[wpos++] = '\n'; |
1046 break; | 1133 break; |
1047 case 27: /* /FONT */ | 1134 case 27: /* /FONT */ |
1048 if (fonts) { | 1135 if (fonts) { |
1049 FontDetail *font = fonts->data; | 1136 GtkIMHtmlFontDetail *font = fonts->data; |
1050 NEW_BIT (NEW_TEXT_BIT); | 1137 NEW_BIT (NEW_TEXT_BIT); |
1051 fonts = g_slist_remove (fonts, font); | 1138 fonts = g_slist_remove (fonts, font); |
1052 if (font->face) | 1139 if (font->face) |
1053 g_free (font->face); | 1140 g_free (font->face); |
1054 if (font->fore) | 1141 if (font->fore) |
1090 case 41: /* /BINARY */ | 1177 case 41: /* /BINARY */ |
1091 break; | 1178 break; |
1092 case 43: /* FONT (opt) */ | 1179 case 43: /* FONT (opt) */ |
1093 { | 1180 { |
1094 gchar *color, *back, *face, *size, *sml; | 1181 gchar *color, *back, *face, *size, *sml; |
1095 FontDetail *font, *oldfont = NULL; | 1182 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
1096 color = gtk_imhtml_get_html_opt (tag, "COLOR="); | 1183 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
1097 back = gtk_imhtml_get_html_opt (tag, "BACK="); | 1184 back = gtk_imhtml_get_html_opt (tag, "BACK="); |
1098 face = gtk_imhtml_get_html_opt (tag, "FACE="); | 1185 face = gtk_imhtml_get_html_opt (tag, "FACE="); |
1099 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | 1186 size = gtk_imhtml_get_html_opt (tag, "SIZE="); |
1100 sml = gtk_imhtml_get_html_opt (tag, "SML="); | 1187 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
1101 if (!(color || back || face || size || sml)) | 1188 if (!(color || back || face || size || sml)) |
1102 break; | 1189 break; |
1103 | 1190 |
1104 NEW_BIT (NEW_TEXT_BIT); | 1191 NEW_BIT (NEW_TEXT_BIT); |
1105 | 1192 |
1106 font = g_new0 (FontDetail, 1); | 1193 font = g_new0 (GtkIMHtmlFontDetail, 1); |
1107 if (fonts) | 1194 if (fonts) |
1108 oldfont = fonts->data; | 1195 oldfont = fonts->data; |
1109 | 1196 |
1110 if (color && !(options & GTK_IMHTML_NO_COLOURS)) | 1197 if (color && !(options & GTK_IMHTML_NO_COLOURS)) |
1111 font->fore = color; | 1198 font->fore = color; |
1196 if (!gdk_pixbuf_loader_write(load, imagedata, im_len, &error)){ | 1283 if (!gdk_pixbuf_loader_write(load, imagedata, im_len, &error)){ |
1197 fprintf(stderr, "IM Image corrupted or unreadable.: %s\n", error->message); | 1284 fprintf(stderr, "IM Image corrupted or unreadable.: %s\n", error->message); |
1198 } else { | 1285 } else { |
1199 imagepb = gdk_pixbuf_loader_get_pixbuf(load); | 1286 imagepb = gdk_pixbuf_loader_get_pixbuf(load); |
1200 if (imagepb) { | 1287 if (imagepb) { |
1201 scalable = gaim_im_image_new(imagepb, g_strdup(src)); | 1288 scalable = gtk_imhtml_image_new(imagepb, g_strdup(src)); |
1202 NEW_BIT(NEW_SCALABLE_BIT); | 1289 NEW_BIT(NEW_SCALABLE_BIT); |
1203 g_object_unref(imagepb); | 1290 g_object_unref(imagepb); |
1204 } | 1291 } |
1205 } | 1292 } |
1206 | 1293 |
1250 NEW_BIT (NEW_TEXT_BIT); | 1337 NEW_BIT (NEW_TEXT_BIT); |
1251 } | 1338 } |
1252 c++; | 1339 c++; |
1253 pos++; | 1340 pos++; |
1254 } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) { | 1341 } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) { |
1255 FontDetail *fd; | 1342 GtkIMHtmlFontDetail *fd; |
1256 gchar *sml = NULL; | 1343 gchar *sml = NULL; |
1257 if (fonts) { | 1344 if (fonts) { |
1258 fd = fonts->data; | 1345 fd = fonts->data; |
1259 sml = fd->sml; | 1346 sml = fd->sml; |
1260 } | 1347 } |
1279 if (str) | 1366 if (str) |
1280 str = g_string_append (str, "</A>"); | 1367 str = g_string_append (str, "</A>"); |
1281 } | 1368 } |
1282 | 1369 |
1283 while (fonts) { | 1370 while (fonts) { |
1284 FontDetail *font = fonts->data; | 1371 GtkIMHtmlFontDetail *font = fonts->data; |
1285 fonts = g_slist_remove (fonts, font); | 1372 fonts = g_slist_remove (fonts, font); |
1286 if (font->face) | 1373 if (font->face) |
1287 g_free (font->face); | 1374 g_free (font->face); |
1288 if (font->fore) | 1375 if (font->fore) |
1289 g_free (font->fore); | 1376 g_free (font->fore); |
1390 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | 1477 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, |
1391 rect.y + rect.height); | 1478 rect.y + rect.height); |
1392 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | 1479 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); |
1393 } | 1480 } |
1394 | 1481 |
1395 static gint | 1482 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
1396 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | 1483 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, gchar *filename) |
1397 { | 1484 { |
1398 PangoLayout *layout; | 1485 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
1399 | |
1400 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
1401 | |
1402 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
1403 | |
1404 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, | |
1405 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, | |
1406 "tooltip", 0, 0, -1, -1); | |
1407 | |
1408 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
1409 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
1410 | |
1411 g_object_unref(layout); | |
1412 return FALSE; | |
1413 } | |
1414 | |
1415 static gint | |
1416 gtk_imhtml_tip (gpointer data) | |
1417 { | |
1418 GtkIMHtml *imhtml = data; | |
1419 PangoFontMetrics *font; | |
1420 PangoLayout *layout; | |
1421 | |
1422 gint gap, x, y, h, w, scr_w, baseline_skip; | |
1423 | |
1424 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
1425 | |
1426 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
1427 imhtml->tip_timer = 0; | |
1428 return FALSE; | |
1429 } | |
1430 | |
1431 if (imhtml->tip_window){ | |
1432 gtk_widget_destroy (imhtml->tip_window); | |
1433 imhtml->tip_window = NULL; | |
1434 } | |
1435 | |
1436 imhtml->tip_timer = 0; | |
1437 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
1438 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
1439 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
1440 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
1441 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
1442 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
1443 | |
1444 gtk_widget_ensure_style (imhtml->tip_window); | |
1445 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
1446 font = pango_font_get_metrics(pango_context_load_font(pango_layout_get_context(layout), | |
1447 imhtml->tip_window->style->font_desc), | |
1448 NULL); | |
1449 | |
1450 | |
1451 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
1452 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + | |
1453 pango_font_metrics_get_descent(font))/ 4); | |
1454 | |
1455 if (gap < 2) | |
1456 gap = 2; | |
1457 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
1458 pango_font_metrics_get_descent(font)); | |
1459 w = 8 + scr_w; | |
1460 h = 8 + baseline_skip; | |
1461 | |
1462 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
1463 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
1464 y += GTK_WIDGET(imhtml)->allocation.y; | |
1465 | |
1466 scr_w = gdk_screen_width(); | |
1467 | |
1468 x -= ((w >> 1) + 4); | |
1469 | |
1470 if ((x + w) > scr_w) | |
1471 x -= (x + w) - scr_w; | |
1472 else if (x < 0) | |
1473 x = 0; | |
1474 | |
1475 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
1476 pango_font_metrics_get_descent(font)); | |
1477 | |
1478 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
1479 gtk_widget_show (imhtml->tip_window); | |
1480 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
1481 | |
1482 pango_font_metrics_unref(font); | |
1483 g_object_unref(layout); | |
1484 | |
1485 return FALSE; | |
1486 } | |
1487 | |
1488 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data) | |
1489 { | |
1490 GdkRectangle rect; | |
1491 | |
1492 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect); | |
1493 if(widget->old_rect.width != rect.width || widget->old_rect.height != rect.height){ | |
1494 GList *iter = GTK_IMHTML(widget)->scalables; | |
1495 | |
1496 while(iter){ | |
1497 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data); | |
1498 scale->scale(scale, rect.width, rect.height); | |
1499 | |
1500 iter = iter->next; | |
1501 } | |
1502 } | |
1503 | |
1504 widget->old_rect = rect; | |
1505 return FALSE; | |
1506 } | |
1507 | |
1508 /* GtkIMHtmlScalable, gaim_im_image, gaim_hr */ | |
1509 GtkIMHtmlScalable *gaim_im_image_new(GdkPixbuf *img, gchar *filename) | |
1510 { | |
1511 gaim_im_image *im_image = g_malloc(sizeof(gaim_im_image)); | |
1512 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); | 1486 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
1513 | 1487 |
1514 GTK_IMHTML_SCALABLE(im_image)->scale = gaim_im_image_scale; | 1488 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
1515 GTK_IMHTML_SCALABLE(im_image)->add_to = gaim_im_image_add_to; | 1489 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; |
1516 GTK_IMHTML_SCALABLE(im_image)->free = gaim_im_image_free; | 1490 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; |
1517 | 1491 |
1518 im_image->pixbuf = img; | 1492 im_image->pixbuf = img; |
1519 im_image->image = image; | 1493 im_image->image = image; |
1520 im_image->width = gdk_pixbuf_get_width(img); | 1494 im_image->width = gdk_pixbuf_get_width(img); |
1521 im_image->height = gdk_pixbuf_get_height(img); | 1495 im_image->height = gdk_pixbuf_get_height(img); |
1524 | 1498 |
1525 g_object_ref(img); | 1499 g_object_ref(img); |
1526 return GTK_IMHTML_SCALABLE(im_image); | 1500 return GTK_IMHTML_SCALABLE(im_image); |
1527 } | 1501 } |
1528 | 1502 |
1529 void gaim_im_image_scale(GtkIMHtmlScalable *scale, int width, int height) | 1503 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
1530 { | 1504 { |
1531 gaim_im_image *image = (gaim_im_image *)scale; | 1505 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
1532 | 1506 |
1533 if(image->width > width || image->height > height){ | 1507 if(image->width > width || image->height > height){ |
1534 GdkPixbuf *new_image = NULL; | 1508 GdkPixbuf *new_image = NULL; |
1535 float factor; | 1509 float factor; |
1536 int new_width = image->width, new_height = image->height; | 1510 int new_width = image->width, new_height = image->height; |
1550 gtk_image_set_from_pixbuf(image->image, new_image); | 1524 gtk_image_set_from_pixbuf(image->image, new_image); |
1551 g_object_unref(G_OBJECT(new_image)); | 1525 g_object_unref(G_OBJECT(new_image)); |
1552 } | 1526 } |
1553 } | 1527 } |
1554 | 1528 |
1555 void gaim_im_image_free(GtkIMHtmlScalable *scale) | |
1556 { | |
1557 gaim_im_image *image = (gaim_im_image *)scale; | |
1558 | |
1559 g_object_unref(image->pixbuf); | |
1560 g_free(image->filename); | |
1561 g_free(scale); | |
1562 } | |
1563 | |
1564 void gaim_im_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1565 { | |
1566 gaim_im_image *image = (gaim_im_image *)scale; | |
1567 GtkWidget *box = gtk_event_box_new(); | |
1568 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1569 | |
1570 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
1571 | |
1572 gtk_widget_show(GTK_WIDGET(image->image)); | |
1573 gtk_widget_show(box); | |
1574 | |
1575 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); | |
1576 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gaim_im_image_clicked), image); | |
1577 } | |
1578 | |
1579 GtkIMHtmlScalable *gaim_hr_new() | |
1580 { | |
1581 gaim_hr *hr = g_malloc(sizeof(gaim_hr)); | |
1582 | |
1583 GTK_IMHTML_SCALABLE(hr)->scale = gaim_hr_scale; | |
1584 GTK_IMHTML_SCALABLE(hr)->add_to = gaim_hr_add_to; | |
1585 GTK_IMHTML_SCALABLE(hr)->free = gaim_hr_free; | |
1586 | |
1587 hr->sep = gtk_hseparator_new(); | |
1588 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
1589 gtk_widget_show(hr->sep); | |
1590 | |
1591 return GTK_IMHTML_SCALABLE(hr); | |
1592 } | |
1593 | |
1594 void gaim_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
1595 { | |
1596 gtk_widget_set_size_request(((gaim_hr *)scale)->sep, width, 2); | |
1597 } | |
1598 | |
1599 void gaim_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1600 { | |
1601 gaim_hr *hr = (gaim_hr *)scale; | |
1602 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1603 | |
1604 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); | |
1605 } | |
1606 | |
1607 void gaim_hr_free(GtkIMHtmlScalable *scale) | |
1608 { | |
1609 /* gtk_widget_destroy(((gaim_hr *)scale)->sep); */ | |
1610 g_free(scale); | |
1611 } | |
1612 | |
1613 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel) | 1529 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel) |
1614 { | 1530 { |
1615 const gchar *filename = gtk_file_selection_get_filename(sel); | 1531 const gchar *filename = gtk_file_selection_get_filename(sel); |
1616 gaim_im_image *image = g_object_get_data(G_OBJECT(sel), "gaim_im_image"); | 1532 gchar *dirname; |
1533 GtkIMHtmlImage *image = g_object_get_data(G_OBJECT(sel), "GtkIMHtmlImage"); | |
1617 gchar *type = NULL; | 1534 gchar *type = NULL; |
1618 GError *error = NULL; | 1535 GError *error = NULL; |
1619 #if GTK_CHECK_VERSION(2,2,0) | 1536 #if GTK_CHECK_VERSION(2,2,0) |
1620 GSList *formats = gdk_pixbuf_get_formats(); | 1537 GSList *formats = gdk_pixbuf_get_formats(); |
1621 #endif | 1538 #endif |
1622 | 1539 |
1623 if (gaim_gtk_check_if_dir(filename, GTK_FILE_SELECTION(sel))) | 1540 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { |
1541 /* append a / if needed */ | |
1542 if (filename[strlen(filename) - 1] != '/') { | |
1543 dirname = g_strconcat(filename, "/", NULL); | |
1544 } else { | |
1545 dirname = g_strdup(filename); | |
1546 } | |
1547 gtk_file_selection_set_filename(sel, dirname); | |
1548 g_free(dirname); | |
1624 return; | 1549 return; |
1550 } | |
1625 | 1551 |
1626 #if GTK_CHECK_VERSION(2,2,0) | 1552 #if GTK_CHECK_VERSION(2,2,0) |
1627 while(formats){ | 1553 while(formats){ |
1628 GdkPixbufFormat *format = formats->data; | 1554 GdkPixbufFormat *format = formats->data; |
1629 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | 1555 gchar **extensions = gdk_pixbuf_format_get_extensions(format); |
1668 | 1594 |
1669 /* If I can't find a valid type, I will just tell the user about it and then assume | 1595 /* If I can't find a valid type, I will just tell the user about it and then assume |
1670 it's a png */ | 1596 it's a png */ |
1671 if(!type){ | 1597 if(!type){ |
1672 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | 1598 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, |
1673 _("Gaim was unable to guess the image type base on the file extension supplied. Defaulting to PNG.")); | 1599 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
1674 type = g_strdup("png"); | 1600 type = g_strdup("png"); |
1675 } | 1601 } |
1676 | 1602 |
1677 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); | 1603 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
1678 | 1604 |
1683 } | 1609 } |
1684 | 1610 |
1685 g_free(type); | 1611 g_free(type); |
1686 } | 1612 } |
1687 | 1613 |
1688 static void gaim_im_image_save(GtkWidget *w, gaim_im_image *image) | 1614 static void gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) |
1689 { | 1615 { |
1690 GtkWidget *sel = gtk_file_selection_new(_("Gaim - Save Image")); | 1616 GtkWidget *sel = gtk_file_selection_new(_("Save Image")); |
1691 | 1617 |
1692 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename); | 1618 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename); |
1693 g_object_set_data(G_OBJECT(sel), "gaim_im_image", image); | 1619 g_object_set_data(G_OBJECT(sel), "GtkIMHtmlImage", image); |
1694 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", | 1620 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", |
1695 G_CALLBACK(write_img_to_file), sel); | 1621 G_CALLBACK(write_img_to_file), sel); |
1696 | 1622 |
1697 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", | 1623 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", |
1698 G_CALLBACK(gtk_widget_destroy), sel); | 1624 G_CALLBACK(gtk_widget_destroy), sel); |
1700 G_CALLBACK(gtk_widget_destroy), sel); | 1626 G_CALLBACK(gtk_widget_destroy), sel); |
1701 | 1627 |
1702 gtk_widget_show(sel); | 1628 gtk_widget_show(sel); |
1703 } | 1629 } |
1704 | 1630 |
1705 static gboolean gaim_im_image_clicked(GtkWidget *w, GdkEvent *event, gaim_im_image *image) | 1631 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
1706 { | 1632 { |
1707 GdkEventButton *event_button = (GdkEventButton *) event; | 1633 GdkEventButton *event_button = (GdkEventButton *) event; |
1708 | 1634 |
1709 if (event->type == GDK_BUTTON_RELEASE) { | 1635 if (event->type == GDK_BUTTON_RELEASE) { |
1710 if(event_button->button == 3) { | 1636 if(event_button->button == 3) { |
1714 | 1640 |
1715 /* buttons and such */ | 1641 /* buttons and such */ |
1716 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | 1642 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); |
1717 item = gtk_image_menu_item_new_with_mnemonic(text); | 1643 item = gtk_image_menu_item_new_with_mnemonic(text); |
1718 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | 1644 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
1719 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gaim_im_image_save), image); | 1645 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
1720 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | 1646 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
1721 | 1647 |
1722 gtk_widget_show_all(menu); | 1648 gtk_widget_show_all(menu); |
1723 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | 1649 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
1724 event_button->button, event_button->time); | 1650 event_button->button, event_button->time); |
1732 be caught by the regular GtkTextView menu */ | 1658 be caught by the regular GtkTextView menu */ |
1733 else | 1659 else |
1734 return FALSE; /* Let clicks go through if we didn't catch anything */ | 1660 return FALSE; /* Let clicks go through if we didn't catch anything */ |
1735 | 1661 |
1736 } | 1662 } |
1663 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) | |
1664 { | |
1665 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
1666 | |
1667 g_object_unref(image->pixbuf); | |
1668 g_free(image->filename); | |
1669 g_free(scale); | |
1670 } | |
1671 | |
1672 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1673 { | |
1674 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
1675 GtkWidget *box = gtk_event_box_new(); | |
1676 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1677 | |
1678 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
1679 | |
1680 gtk_widget_show(GTK_WIDGET(image->image)); | |
1681 gtk_widget_show(box); | |
1682 | |
1683 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); | |
1684 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
1685 } | |
1686 | |
1687 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
1688 { | |
1689 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
1690 | |
1691 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
1692 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
1693 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
1694 | |
1695 hr->sep = gtk_hseparator_new(); | |
1696 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
1697 gtk_widget_show(hr->sep); | |
1698 | |
1699 return GTK_IMHTML_SCALABLE(hr); | |
1700 } | |
1701 | |
1702 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
1703 { | |
1704 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width, 2); | |
1705 } | |
1706 | |
1707 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1708 { | |
1709 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
1710 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1711 | |
1712 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); | |
1713 } | |
1714 | |
1715 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
1716 { | |
1717 /* gtk_widget_destroy(((GtkIMHtmlHr *)scale)->sep); */ | |
1718 g_free(scale); | |
1719 } |