comparison src/buddy.c @ 4724:b9e7ccf21f9c

[gaim-migrate @ 5037] I stayed up all night and readded tooltips. It feels great. GTK 2 provides no easy way to add a tooltip to a row of a GtkTreeView so I had to do it all by hand. In doing so, I took some liberties and did some stuff most tooltips can't do... my tooltips have Markup and Pixbufs in them =-). Tomorrow, KingAnt gets back. I'll let him readd the AIM-specific tooltip stuff. Capabilities and logged on time used to live in the buddy struct, but were removed for being too aim-centric. KingAnt will put them back, I'm sure. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Wed, 12 Mar 2003 11:37:31 +0000
parents 534eaa4ead94
children fd44726a527f
comparison
equal deleted inserted replaced
4723:39068784aa08 4724:b9e7ccf21f9c
58 58
59 /* Docklet nonsense */ 59 /* Docklet nonsense */
60 static gboolean gaim_gtk_blist_obscured = FALSE; 60 static gboolean gaim_gtk_blist_obscured = FALSE;
61 61
62 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node); 62 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node);
63 static char *gaim_get_tooltip_text(struct buddy *b);
64 static GdkPixbuf *gaim_gtk_blist_get_status_icon(struct buddy *b, GaimStatusIconSize size);
63 65
64 /*************************************************** 66 /***************************************************
65 * Callbacks * 67 * Callbacks *
66 ***************************************************/ 68 ***************************************************/
67 69
334 gtk_tree_path_free(path); 336 gtk_tree_path_free(path);
335 } 337 }
336 } 338 }
337 } 339 }
338 340
341 static void gaim_gtk_blist_paint_tip(GtkWidget *widget, GdkEventExpose *event, struct buddy *b)
342 {
343 int x,y,scr_w,scr_h, w, h;
344 GtkStyle *style;
345 GdkPixbuf *pixbuf = gaim_gtk_blist_get_status_icon(b, GAIM_STATUS_ICON_LARGE);
346 PangoLayout *layout;
347 char *tooltiptext = gaim_get_tooltip_text(b);
348
349 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL);
350 pango_layout_set_markup(layout, tooltiptext, strlen(tooltiptext));
351 style = gtkblist->tipwindow->style;
352
353 gtk_paint_flat_box (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
354 NULL, gtkblist->tipwindow, "tooltip", 0, 0, -1, -1);
355
356 gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, pixbuf,
357 0, 0, 4, 4, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
358
359 gtk_paint_layout (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, TRUE,
360 NULL, gtkblist->tipwindow, "tooltip", 38, 4, layout);
361
362 g_object_unref (pixbuf);
363 g_object_unref (layout);
364 g_free(tooltiptext);
365 return;
366 }
367
368 static gboolean gaim_gtk_blist_tooltip_timeout(GtkWidget *tv)
369 {
370 GtkTreePath *path;
371 GtkTreeIter iter;
372 GaimBlistNode *node;
373 char *tooltiptext;
374 GValue val = {0};
375
376 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->rect.x, gtkblist->rect.y, &path, NULL, NULL, NULL))
377 return FALSE;
378 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path);
379 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val);
380 node = g_value_get_pointer(&val);
381
382 if (GAIM_BLIST_NODE_IS_BUDDY(node)) {
383 int scr_w,scr_h, w, h, x, y;
384 PangoLayout *layout;
385 struct buddy *buddy = (struct buddy*)node;
386 char *tooltiptext = gaim_get_tooltip_text(buddy);
387 gtkblist->tipwindow = gtk_window_new(GTK_WINDOW_POPUP);
388 gtk_widget_set_app_paintable(gtkblist->tipwindow, TRUE);
389 gtk_window_set_policy(GTK_WINDOW(gtkblist->tipwindow), FALSE, FALSE, TRUE);
390 gtk_widget_set_name(gtkblist->tipwindow, "gtk-tooltips");
391 g_signal_connect(G_OBJECT(gtkblist->tipwindow), "expose_event",
392 G_CALLBACK(gaim_gtk_blist_paint_tip), buddy);
393 gtk_widget_ensure_style (gtkblist->tipwindow);
394
395 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL);
396 pango_layout_set_markup(layout, tooltiptext, strlen(tooltiptext));
397 scr_w = gdk_screen_width();
398 scr_h = gdk_screen_height();
399 pango_layout_get_size (layout, &w, &h);
400 w = PANGO_PIXELS(w) + 8;
401 h = PANGO_PIXELS(h) + 8;
402
403 /* 38 is the size of a large status icon plus 4 pixels padding on each side.
404 I should #define this or something */
405 w = w + 38;
406 h = MAX(h, 38);
407
408 gdk_window_get_pointer(NULL, &x, &y, NULL);
409 if (GTK_WIDGET_NO_WINDOW(gtkblist->window))
410 y+=gtkblist->window->allocation.y;
411
412 x -= ((w >> 1) + 4);
413
414 if ((x + w) > scr_w)
415 x -= (x + w) - scr_w;
416 else if (x < 0)
417 x = 0;
418
419 if ((y + h + 4) > scr_h)
420 y = y - h;
421 else
422 y = y + 6;
423 g_object_unref (layout);
424 g_free(tooltiptext);
425 gtk_widget_set_size_request(gtkblist->tipwindow, w, h);
426 gtk_widget_set_uposition(gtkblist->tipwindow, x, y);
427 gtk_widget_show(gtkblist->tipwindow);
428 }
429
430 gtk_tree_path_free(path);
431 return FALSE;
432 }
433
434 static void gaim_gtk_blist_motion_cb (GtkWidget *tv, GdkEventMotion *event, gpointer null)
435 {
436 GtkTreePath *path;
437
438 if (gtkblist->timeout) {
439 if ((event->y > gtkblist->rect.y) && ((event->y - gtkblist->rect.height) < gtkblist->rect.y))
440 return;
441 /* We've left the cell. Remove the timeout and create a new one below */
442 if (gtkblist->tipwindow) {
443 gtk_widget_destroy(gtkblist->tipwindow);
444 gtkblist->tipwindow = NULL;
445 }
446
447 g_source_remove(gtkblist->timeout);
448 }
449
450 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL);
451 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &gtkblist->rect);
452 if (path)
453 gtk_tree_path_free(path);
454 gtkblist->timeout = g_timeout_add(500, (GSourceFunc)gaim_gtk_blist_tooltip_timeout, tv);
455 }
456
457 static void gaim_gtk_blist_leave_cb (GtkWidget *w, GdkEventCrossing *e, gpointer n)
458 {
459 if (gtkblist->timeout == 0)
460 return;
461 if (gtkblist->tipwindow) {
462 gtk_widget_destroy(gtkblist->tipwindow);
463 gtkblist->tipwindow = NULL;
464 }
465 g_source_remove(gtkblist->timeout);
466 gtkblist->timeout = 0;
467 }
468
339 /*************************************************** 469 /***************************************************
340 * Crap * 470 * Crap *
341 ***************************************************/ 471 ***************************************************/
342 static GtkItemFactoryEntry blist_menu[] = 472 static GtkItemFactoryEntry blist_menu[] =
343 { 473 {
383 513
384 /********************************************************* 514 /*********************************************************
385 * Private Utility functions * 515 * Private Utility functions *
386 *********************************************************/ 516 *********************************************************/
387 517
388 static GdkPixbuf *gaim_gtk_blist_get_status_icon(struct buddy *b) 518 static char *gaim_get_tooltip_text(struct buddy *b)
519 {
520 char *text = NULL;
521 struct prpl* prpl = find_prpl(b->account->protocol);
522 char *statustext = NULL;
523 char *tooltiptext = NULL;
524 char *warning = NULL, *idletime = NULL;
525
526 if (prpl->tooltip_text) {
527 char *tmp = prpl->tooltip_text(b);
528 if (tmp) {
529 statustext = g_markup_escape_text(tmp, strlen(tmp));
530 g_free(tmp);
531 }
532 }
533
534 if (b->idle) {
535 int ihrs, imin;
536 time_t t;
537 time(&t);
538 ihrs = (t - b->idle) / 3600;
539 imin = ((t - b->idle) / 60) % 60;
540 if (ihrs)
541 idletime = g_strdup_printf(_("<b>Idle</b> %dh%02dm"), ihrs, imin);
542 else
543 idletime = g_strdup_printf(_("<b>Idle</b> %dm"), imin);
544 }
545
546 if (b->evil > 0)
547 warning = g_strdup_printf(_("<b>Warned</b> %d%%"), b->evil);
548
549 text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>"
550 "%s %s %s" /* Alias */
551 "%s %s %s" /* Nickname */
552 "%s %s" /* Idle */
553 "%s %s" /* Warning */
554 "%s %s", /* Status */
555 b->name,
556 b->alias && b->alias[0] ? "\n" : "", b->alias && b->alias[0] ? _("<b>Alias</b> ") : "", b->alias ? b->alias : "",
557 b->server_alias ? "\n" : "", b->server_alias ? _("<b>Nickname</b> ") : "", b->server_alias ? b->server_alias : "",
558 b->idle ? "\n" : "", b->idle ? idletime : "",
559 b->evil ? "\n" : "", b->evil ? warning : "",
560 statustext ? "\n" : "", statustext ? statustext : "");
561 return text;
562
563 }
564
565 static GdkPixbuf *gaim_gtk_blist_get_status_icon(struct buddy *b, GaimStatusIconSize size)
389 { 566 {
390 GdkPixbuf *status = NULL; 567 GdkPixbuf *status = NULL;
391 GdkPixbuf *scale = NULL; 568 GdkPixbuf *scale = NULL;
392 GdkPixbuf *emblem = NULL; 569 GdkPixbuf *emblem = NULL;
393 gchar *filename = NULL; 570 gchar *filename = NULL;
401 if (prpl->list_icon) 578 if (prpl->list_icon)
402 protoname = prpl->list_icon(b->account, b); 579 protoname = prpl->list_icon(b->account, b);
403 if (prpl->list_emblems) 580 if (prpl->list_emblems)
404 prpl->list_emblems(b, &se, &sw, &nw, &ne); 581 prpl->list_emblems(b, &se, &sw, &nw, &ne);
405 582
406 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) { 583 if (size == GAIM_STATUS_ICON_SMALL) {
407 scalesize = 15; 584 scalesize = 15;
408 sw = nw = ne = NULL; /* So that only the se icon will composite */ 585 sw = nw = ne = NULL; /* So that only the se icon will composite */
409 } 586 }
410 587
411 588
447 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); 624 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL);
448 g_free(image); 625 g_free(image);
449 emblem = gdk_pixbuf_new_from_file(filename,NULL); 626 emblem = gdk_pixbuf_new_from_file(filename,NULL);
450 g_free(filename); 627 g_free(filename);
451 if (emblem) { 628 if (emblem) {
452 if (blist_options & OPT_BLIST_SHOW_ICONS) 629 if (size == GAIM_STATUS_ICON_LARGE)
453 gdk_pixbuf_composite (emblem, 630 gdk_pixbuf_composite (emblem,
454 scale, 15, 15, 631 scale, 15, 15,
455 15, 15, 632 15, 15,
456 15, 15, 633 15, 15,
457 1, 1, 634 1, 1,
548 struct prpl* prpl = find_prpl(b->account->protocol); 725 struct prpl* prpl = find_prpl(b->account->protocol);
549 726
550 /* XXX Clean up this crap */ 727 /* XXX Clean up this crap */
551 728
552 int ihrs, imin; 729 int ihrs, imin;
553 char *idletime = NULL, *warning = NULL; 730 char *idletime = NULL, *warning = NULL, *statustext = NULL;
554 const char *statustext = NULL;
555 time_t t; 731 time_t t;
556 732
557 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) { 733 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) {
558 if (b->idle > 0 && blist_options & OPT_BLIST_GREY_IDLERS) { 734 if (b->idle > 0 && blist_options & OPT_BLIST_GREY_IDLERS) {
559 text = g_strdup_printf("<span color='dim grey'>%s</span>", 735 text = g_strdup_printf("<span color='dim grey'>%s</span>",
568 time(&t); 744 time(&t);
569 ihrs = (t - b->idle) / 3600; 745 ihrs = (t - b->idle) / 3600;
570 imin = ((t - b->idle) / 60) % 60; 746 imin = ((t - b->idle) / 60) % 60;
571 747
572 if (prpl->status_text) { 748 if (prpl->status_text) {
573 char *tmp = prpl->status_text(b); 749 const char *tmp = prpl->status_text(b);
574 if (tmp) 750 if (tmp)
575 statustext = g_markup_escape_text(tmp, strlen(tmp)); 751 statustext = g_markup_escape_text(tmp, strlen(tmp));
576 } 752 }
577 753
578 if (b->idle) { 754 if (b->idle) {
679 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(gtkblist->treeview), gte, 2, 855 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(gtkblist->treeview), gte, 2,
680 GDK_ACTION_COPY | GDK_ACTION_MOVE); 856 GDK_ACTION_COPY | GDK_ACTION_MOVE);
681 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-received", G_CALLBACK(gaim_gtk_blist_drag_data_rcv_cb), NULL); 857 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-received", G_CALLBACK(gaim_gtk_blist_drag_data_rcv_cb), NULL);
682 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-get", G_CALLBACK(gaim_gtk_blist_drag_data_get_cb), NULL); 858 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-get", G_CALLBACK(gaim_gtk_blist_drag_data_get_cb), NULL);
683 859
860 /* Tooltips */
861 g_signal_connect(G_OBJECT(gtkblist->treeview), "motion-notify-event", G_CALLBACK(gaim_gtk_blist_motion_cb), NULL);
862 g_signal_connect(G_OBJECT(gtkblist->treeview), "leave-notify-event", G_CALLBACK(gaim_gtk_blist_leave_cb), NULL);
684 863
685 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE); 864 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE);
686 865
687 rend = gtk_cell_renderer_pixbuf_new(); 866 rend = gtk_cell_renderer_pixbuf_new();
688 column = gtk_tree_view_column_new_with_attributes("Status", rend, "pixbuf", STATUS_ICON_COLUMN, NULL); 867 column = gtk_tree_view_column_new_with_attributes("Status", rend, "pixbuf", STATUS_ICON_COLUMN, NULL);
901 if (GAIM_BLIST_NODE_IS_BUDDY(node) && ((struct buddy*)node)->present) { 1080 if (GAIM_BLIST_NODE_IS_BUDDY(node) && ((struct buddy*)node)->present) {
902 GdkPixbuf *status, *avatar; 1081 GdkPixbuf *status, *avatar;
903 char *mark; 1082 char *mark;
904 char *warning = NULL, *idle = NULL; 1083 char *warning = NULL, *idle = NULL;
905 1084
906 status = gaim_gtk_blist_get_status_icon((struct buddy*)node); 1085 status = gaim_gtk_blist_get_status_icon((struct buddy*)node,
1086 blist_options & OPT_BLIST_SHOW_ICONS ? GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL);
907 avatar = gaim_gtk_blist_get_buddy_icon((struct buddy*)node); 1087 avatar = gaim_gtk_blist_get_buddy_icon((struct buddy*)node);
908 mark = gaim_gtk_blist_get_name_markup((struct buddy*)node); 1088 mark = gaim_gtk_blist_get_name_markup((struct buddy*)node);
909 1089
910 if ((((struct buddy*)node)->idle > 0) && 1090 if ((((struct buddy*)node)->idle > 0) &&
911 (!(blist_options & OPT_BLIST_SHOW_ICONS) && (blist_options & OPT_BLIST_SHOW_IDLETIME))) { 1091 (!(blist_options & OPT_BLIST_SHOW_ICONS) && (blist_options & OPT_BLIST_SHOW_IDLETIME))) {