Mercurial > pidgin
comparison src/gtkimhtml.c @ 4735:66c2388046fb
[gaim-migrate @ 5050]
This patch is from Ka-Hing Cheung. It readds tooltips and the hand cursor
for GtkIMHtml links.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Thu, 13 Mar 2003 06:56:40 +0000 |
parents | 42d53c416bb9 |
children | beffb3109ddb |
comparison
equal
deleted
inserted
replaced
4734:ece4045eebff | 4735:66c2388046fb |
---|---|
46 #else | 46 #else |
47 # define N_(String) (String) | 47 # define N_(String) (String) |
48 # define _(x) (x) | 48 # define _(x) (x) |
49 #endif | 49 #endif |
50 | 50 |
51 #include <pango/pango-font.h> | |
52 | |
53 #define TOOLTIP_TIMEOUT 500 | |
54 | |
55 static gint gtk_imhtml_tip (gpointer data); | |
56 | |
51 | 57 |
52 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a | 58 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
53 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ | 59 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ |
54 #define MAX_FONT_SIZE 7 | 60 #define MAX_FONT_SIZE 7 |
55 #define POINT_SIZE(x) (_point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) | 61 #define POINT_SIZE(x) (_point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
156 g_hash_table_foreach_remove(imhtml->smiley_data, gtk_smiley_tree_destroy_from_hash, NULL); | 162 g_hash_table_foreach_remove(imhtml->smiley_data, gtk_smiley_tree_destroy_from_hash, NULL); |
157 g_hash_table_destroy(imhtml->smiley_data); | 163 g_hash_table_destroy(imhtml->smiley_data); |
158 gtk_smiley_tree_destroy(imhtml->default_smilies); | 164 gtk_smiley_tree_destroy(imhtml->default_smilies); |
159 gdk_cursor_unref(imhtml->hand_cursor); | 165 gdk_cursor_unref(imhtml->hand_cursor); |
160 gdk_cursor_unref(imhtml->arrow_cursor); | 166 gdk_cursor_unref(imhtml->arrow_cursor); |
167 if(imhtml->tip_window){ | |
168 gtk_widget_destroy(imhtml->tip_window); | |
169 } | |
170 if(imhtml->tip_timer) | |
171 gtk_timeout_remove(imhtml->tip_timer); | |
172 | |
161 G_OBJECT_CLASS(parent_class)->finalize (object); | 173 G_OBJECT_CLASS(parent_class)->finalize (object); |
162 } | 174 } |
163 | 175 |
164 /* Boring GTK stuff */ | 176 /* Boring GTK stuff */ |
165 static void gtk_imhtml_class_init (GtkIMHtmlClass *class) | 177 static void gtk_imhtml_class_init (GtkIMHtmlClass *class) |
211 imhtml->show_smileys = TRUE; | 223 imhtml->show_smileys = TRUE; |
212 imhtml->show_comments = TRUE; | 224 imhtml->show_comments = TRUE; |
213 | 225 |
214 imhtml->smiley_data = g_hash_table_new (g_str_hash, g_str_equal); | 226 imhtml->smiley_data = g_hash_table_new (g_str_hash, g_str_equal); |
215 imhtml->default_smilies = gtk_smiley_tree_new(); | 227 imhtml->default_smilies = gtk_smiley_tree_new(); |
228 | |
229 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); | |
230 | |
231 imhtml->tip = NULL; | |
232 imhtml->tip_timer = 0; | |
233 imhtml->tip_window = NULL; | |
216 } | 234 } |
217 | 235 |
218 GtkWidget *gtk_imhtml_new(void *a, void *b) | 236 GtkWidget *gtk_imhtml_new(void *a, void *b) |
219 { | 237 { |
220 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); | 238 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); |
291 | 309 |
292 menu = gtk_menu_new(); | 310 menu = gtk_menu_new(); |
293 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | 311 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
294 event_button->button, event_button->time); | 312 event_button->button, event_button->time); |
295 | 313 |
296 /* URL of link, desensitized */ | |
297 item = gtk_menu_item_new(); | |
298 label = gtk_label_new(url); | |
299 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); | |
300 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); | |
301 gtk_container_add(GTK_CONTAINER(item), label); | |
302 gtk_widget_set_sensitive(item, FALSE); | |
303 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | |
304 | |
305 /* seperator */ | |
306 item = gtk_menu_item_new(); | |
307 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | |
308 | |
309 /* buttons and such */ | 314 /* buttons and such */ |
310 img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU); | 315 img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU); |
311 item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Link Location")); | 316 item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Link Location")); |
312 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | 317 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
313 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), | 318 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), |
322 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | 327 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
323 gtk_widget_show_all(menu); | 328 gtk_widget_show_all(menu); |
324 | 329 |
325 return TRUE; | 330 return TRUE; |
326 } | 331 } |
327 } else if (event->type == GDK_ENTER_NOTIFY) { | |
328 /* make a hand cursor and a tooltip timeout -- if GTK worked as it should */ | |
329 } else if (event->type == GDK_LEAVE_NOTIFY) { | |
330 /* clear timeout and make an arrow cursor again --if GTK worked as it should */ | |
331 } | 332 } |
332 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | 333 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) |
333 return TRUE; /* Clicking the right mouse button on a link shouldn't | 334 return TRUE; /* Clicking the right mouse button on a link shouldn't |
334 be caught by the regular GtkTextView menu */ | 335 be caught by the regular GtkTextView menu */ |
335 else | 336 else |
336 return FALSE; /* Let clicks go through if we didn't catch anything */ | 337 return FALSE; /* Let clicks go through if we didn't catch anything */ |
338 } | |
339 | |
340 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
341 { | |
342 GtkTextIter iter; | |
343 GdkWindow *win = event->window; | |
344 int x, y; | |
345 GSList *tags = NULL, *templist = NULL; | |
346 | |
347 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
348 | |
349 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
350 event->x, event->y, &x, &y); | |
351 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
352 | |
353 if (GTK_IMHTML(imhtml)->tip_window) { | |
354 gtk_widget_destroy (GTK_IMHTML(imhtml)->tip_window); | |
355 GTK_IMHTML(imhtml)->tip_window = NULL; | |
356 } | |
357 if (GTK_IMHTML(imhtml)->tip_timer) { | |
358 gtk_timeout_remove (GTK_IMHTML(imhtml)->tip_timer); | |
359 GTK_IMHTML(imhtml)->tip_timer = 0; | |
360 } | |
361 | |
362 GTK_IMHTML(imhtml)->tip = NULL; | |
363 | |
364 tags = gtk_text_iter_get_tags(&iter); | |
365 | |
366 for(templist = tags; !GTK_IMHTML(imhtml)->tip && templist; templist = templist->next){ | |
367 GtkTextTag *tag = templist->data; | |
368 GTK_IMHTML(imhtml)->tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
369 } | |
370 | |
371 if(GTK_IMHTML(imhtml)->tip){ | |
372 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); | |
373 GTK_IMHTML(imhtml)->tip_timer = gtk_timeout_add (TOOLTIP_TIMEOUT, | |
374 gtk_imhtml_tip, imhtml); | |
375 } | |
376 else{ | |
377 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
378 } | |
379 | |
380 g_slist_free(tags); | |
381 return FALSE; | |
337 } | 382 } |
338 | 383 |
339 /* this isn't used yet | 384 /* this isn't used yet |
340 static void | 385 static void |
341 gtk_smiley_tree_remove (GtkSmileyTree *tree, | 386 gtk_smiley_tree_remove (GtkSmileyTree *tree, |
722 } \ | 767 } \ |
723 if (url) { \ | 768 if (url) { \ |
724 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \ | 769 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \ |
725 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), strdup(url)); \ | 770 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), strdup(url)); \ |
726 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | 771 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
772 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); \ | |
773 g_object_set_data(G_OBJECT(texttag), "link_url", g_strdup(url)); \ | |
774 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
727 } \ | 775 } \ |
728 wpos = 0; \ | 776 wpos = 0; \ |
729 ws[0] = 0; \ | 777 ws[0] = 0; \ |
730 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ | 778 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ |
731 if (x == NEW_HR_BIT) { \ | 779 if (x == NEW_HR_BIT) { \ |
1164 void gtk_imhtml_page_up (GtkIMHtml *imhtml) | 1212 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
1165 { | 1213 { |
1166 | 1214 |
1167 } | 1215 } |
1168 void gtk_imhtml_page_down (GtkIMHtml *imhtml){} | 1216 void gtk_imhtml_page_down (GtkIMHtml *imhtml){} |
1217 | |
1218 static gint | |
1219 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
1220 { | |
1221 PangoLayout *layout; | |
1222 | |
1223 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
1224 | |
1225 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
1226 | |
1227 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, | |
1228 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, | |
1229 "tooltip", 0, 0, -1, -1); | |
1230 | |
1231 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
1232 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
1233 | |
1234 g_free(layout); | |
1235 return FALSE; | |
1236 } | |
1237 | |
1238 static gint | |
1239 gtk_imhtml_tip (gpointer data) | |
1240 { | |
1241 GtkIMHtml *imhtml = data; | |
1242 PangoFontMetrics *font; | |
1243 PangoLayout *layout; | |
1244 | |
1245 gint gap, x, y, h, w, scr_w, baseline_skip; | |
1246 | |
1247 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
1248 | |
1249 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
1250 imhtml->tip_timer = 0; | |
1251 return FALSE; | |
1252 } | |
1253 | |
1254 if (imhtml->tip_window){ | |
1255 gtk_widget_destroy (imhtml->tip_window); | |
1256 imhtml->tip_window = NULL; | |
1257 } | |
1258 | |
1259 imhtml->tip_timer = 0; | |
1260 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
1261 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
1262 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
1263 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
1264 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
1265 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
1266 | |
1267 gtk_widget_ensure_style (imhtml->tip_window); | |
1268 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
1269 font = pango_font_get_metrics(pango_context_load_font(pango_layout_get_context(layout), | |
1270 imhtml->tip_window->style->font_desc), | |
1271 NULL); | |
1272 | |
1273 | |
1274 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
1275 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + | |
1276 pango_font_metrics_get_descent(font))/ 4); | |
1277 | |
1278 if (gap < 2) | |
1279 gap = 2; | |
1280 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
1281 pango_font_metrics_get_descent(font)); | |
1282 w = 8 + scr_w; | |
1283 h = 8 + baseline_skip; | |
1284 | |
1285 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
1286 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
1287 y += GTK_WIDGET(imhtml)->allocation.y; | |
1288 | |
1289 scr_w = gdk_screen_width(); | |
1290 | |
1291 x -= ((w >> 1) + 4); | |
1292 | |
1293 if ((x + w) > scr_w) | |
1294 x -= (x + w) - scr_w; | |
1295 else if (x < 0) | |
1296 x = 0; | |
1297 | |
1298 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
1299 pango_font_metrics_get_descent(font)); | |
1300 | |
1301 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
1302 gtk_widget_show (imhtml->tip_window); | |
1303 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
1304 | |
1305 pango_font_metrics_unref(font); | |
1306 g_free(layout); | |
1307 | |
1308 return FALSE; | |
1309 } |