Mercurial > pidgin.yaz
comparison pidgin/gtkblist.c @ 21877:6bf73aea6450
Some utility functions for showing tooltips. This is used by the buddylist,
the roomlist and the infopane in the conversation window. The userlist in
chats can also use this, I think.
It works OK, but it may be possible to make the code a bit nicer. Any
suggestions?
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Thu, 06 Dec 2007 07:33:53 +0000 |
parents | 6a287408bc54 |
children | f5d961556972 |
comparison
equal
deleted
inserted
replaced
21789:cbf778310bdd | 21877:6bf73aea6450 |
---|---|
57 #include "gtkroomlist.h" | 57 #include "gtkroomlist.h" |
58 #include "gtkstatusbox.h" | 58 #include "gtkstatusbox.h" |
59 #include "gtkscrollbook.h" | 59 #include "gtkscrollbook.h" |
60 #include "gtkutils.h" | 60 #include "gtkutils.h" |
61 #include "pidgin/minidialog.h" | 61 #include "pidgin/minidialog.h" |
62 #include "pidgin/pidgintooltip.h" | |
62 | 63 |
63 #include <gdk/gdkkeysyms.h> | 64 #include <gdk/gdkkeysyms.h> |
64 #include <gtk/gtk.h> | 65 #include <gtk/gtk.h> |
65 #include <gdk/gdk.h> | 66 #include <gdk/gdk.h> |
66 | 67 |
151 static void pidgin_blist_update_group(PurpleBuddyList *list, PurpleBlistNode *node); | 152 static void pidgin_blist_update_group(PurpleBuddyList *list, PurpleBlistNode *node); |
152 static void pidgin_blist_update_contact(PurpleBuddyList *list, PurpleBlistNode *node); | 153 static void pidgin_blist_update_contact(PurpleBuddyList *list, PurpleBlistNode *node); |
153 static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full); | 154 static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full); |
154 static const char *item_factory_translate_func (const char *path, gpointer func_data); | 155 static const char *item_factory_translate_func (const char *path, gpointer func_data); |
155 static gboolean get_iter_from_node(PurpleBlistNode *node, GtkTreeIter *iter); | 156 static gboolean get_iter_from_node(PurpleBlistNode *node, GtkTreeIter *iter); |
157 static gboolean buddy_is_displayable(PurpleBuddy *buddy); | |
156 static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender); | 158 static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender); |
157 static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node); | 159 static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node); |
158 static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded); | 160 static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded); |
159 static void pidgin_blist_expand_contact_cb(GtkWidget *w, PurpleBlistNode *node); | 161 static void pidgin_blist_expand_contact_cb(GtkWidget *w, PurpleBlistNode *node); |
160 | 162 |
2628 g_free(node_name); | 2630 g_free(node_name); |
2629 g_free(tooltip_text); | 2631 g_free(tooltip_text); |
2630 return td; | 2632 return td; |
2631 } | 2633 } |
2632 | 2634 |
2633 static void pidgin_blist_paint_tip(GtkWidget *widget, GdkEventExpose *event, PurpleBlistNode *node) | 2635 static gboolean pidgin_blist_paint_tip(GtkWidget *widget, GdkEventExpose *event, gpointer data) |
2634 { | 2636 { |
2635 GtkStyle *style; | 2637 GtkStyle *style; |
2636 int current_height, max_width; | 2638 int current_height, max_width; |
2637 int max_text_width; | 2639 int max_text_width; |
2638 int max_avatar_width; | 2640 int max_avatar_width; |
2639 GList *l; | 2641 GList *l; |
2640 int prpl_col = 0; | 2642 int prpl_col = 0; |
2641 GtkTextDirection dir = gtk_widget_get_direction(widget); | 2643 GtkTextDirection dir = gtk_widget_get_direction(widget); |
2642 | 2644 |
2643 if(gtkblist->tooltipdata == NULL) | 2645 if(gtkblist->tooltipdata == NULL) |
2644 return; | 2646 return FALSE; |
2645 | 2647 |
2646 style = gtkblist->tipwindow->style; | 2648 style = gtkblist->tipwindow->style; |
2647 gtk_paint_flat_box(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, | 2649 gtk_paint_flat_box(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, |
2648 NULL, gtkblist->tipwindow, "tooltip", 0, 0, -1, -1); | 2650 NULL, gtkblist->tipwindow, "tooltip", 0, 0, -1, -1); |
2649 | 2651 |
2738 td->layout); | 2740 td->layout); |
2739 } | 2741 } |
2740 | 2742 |
2741 current_height += MAX(td->name_height + td->height, td->avatar_height) + TOOLTIP_BORDER; | 2743 current_height += MAX(td->name_height + td->height, td->avatar_height) + TOOLTIP_BORDER; |
2742 } | 2744 } |
2743 } | 2745 return FALSE; |
2744 | 2746 } |
2745 | 2747 |
2746 void pidgin_blist_tooltip_destroy() | 2748 static void |
2749 pidgin_blist_destroy_tooltip_data() | |
2747 { | 2750 { |
2748 while(gtkblist->tooltipdata) { | 2751 while(gtkblist->tooltipdata) { |
2749 struct tooltip_data *td = gtkblist->tooltipdata->data; | 2752 struct tooltip_data *td = gtkblist->tooltipdata->data; |
2750 | 2753 |
2751 if(td->avatar) | 2754 if(td->avatar) |
2757 g_object_unref(td->layout); | 2760 g_object_unref(td->layout); |
2758 g_object_unref(td->name_layout); | 2761 g_object_unref(td->name_layout); |
2759 g_free(td); | 2762 g_free(td); |
2760 gtkblist->tooltipdata = g_list_delete_link(gtkblist->tooltipdata, gtkblist->tooltipdata); | 2763 gtkblist->tooltipdata = g_list_delete_link(gtkblist->tooltipdata, gtkblist->tooltipdata); |
2761 } | 2764 } |
2762 | 2765 } |
2763 if (gtkblist->tipwindow == NULL) | 2766 |
2764 return; | 2767 void pidgin_blist_tooltip_destroy() |
2765 | 2768 { |
2766 gtk_widget_destroy(gtkblist->tipwindow); | 2769 pidgin_blist_destroy_tooltip_data(); |
2767 gtkblist->tipwindow = NULL; | 2770 pidgin_tooltip_destroy(); |
2768 } | 2771 } |
2769 | 2772 |
2770 static gboolean pidgin_blist_expand_timeout(GtkWidget *tv) | 2773 static gboolean |
2771 { | 2774 pidgin_blist_create_tooltip_for_node(GtkWidget *widget, gpointer data, int *w, int *h) |
2772 GtkTreePath *path; | 2775 { |
2773 GtkTreeIter iter; | 2776 PurpleBlistNode *node = data; |
2774 PurpleBlistNode *node; | 2777 int width, height; |
2775 GValue val; | 2778 |
2776 struct _pidgin_blist_node *gtknode; | 2779 gtkblist->tipwindow = widget; |
2777 | |
2778 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y + (gtkblist->tip_rect.height/2), | |
2779 &path, NULL, NULL, NULL)) | |
2780 return FALSE; | |
2781 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
2782 val.g_type = 0; | |
2783 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
2784 node = g_value_get_pointer(&val); | |
2785 | |
2786 if(!PURPLE_BLIST_NODE_IS_CONTACT(node)) { | |
2787 gtk_tree_path_free(path); | |
2788 return FALSE; | |
2789 } | |
2790 | |
2791 gtknode = node->ui_data; | |
2792 | |
2793 if (!gtknode->contact_expanded) { | |
2794 GtkTreeIter i; | |
2795 | |
2796 pidgin_blist_expand_contact_cb(NULL, node); | |
2797 | |
2798 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, >kblist->contact_rect); | |
2799 gdk_drawable_get_size(GDK_DRAWABLE(tv->window), &(gtkblist->contact_rect.width), NULL); | |
2800 gtkblist->mouseover_contact = node; | |
2801 gtk_tree_path_down (path); | |
2802 while (gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &i, path)) { | |
2803 GdkRectangle rect; | |
2804 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect); | |
2805 gtkblist->contact_rect.height += rect.height; | |
2806 gtk_tree_path_next(path); | |
2807 } | |
2808 } | |
2809 gtk_tree_path_free(path); | |
2810 return FALSE; | |
2811 } | |
2812 | |
2813 static gboolean buddy_is_displayable(PurpleBuddy *buddy) | |
2814 { | |
2815 struct _pidgin_blist_node *gtknode; | |
2816 | |
2817 if(!buddy) | |
2818 return FALSE; | |
2819 | |
2820 gtknode = ((PurpleBlistNode*)buddy)->ui_data; | |
2821 | |
2822 return (purple_account_is_connected(buddy->account) && | |
2823 (purple_presence_is_online(buddy->presence) || | |
2824 (gtknode && gtknode->recent_signonoff) || | |
2825 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies") || | |
2826 purple_blist_node_get_bool((PurpleBlistNode*)buddy, "show_offline"))); | |
2827 } | |
2828 | |
2829 static gboolean pidgin_blist_tooltip_timeout(GtkWidget *tv) | |
2830 { | |
2831 GtkTreePath *path; | |
2832 GtkTreeIter iter; | |
2833 PurpleBlistNode *node; | |
2834 GValue val; | |
2835 gboolean editable = FALSE; | |
2836 | |
2837 /* If we're editing a cell (e.g. alias editing), don't show the tooltip */ | |
2838 g_object_get(G_OBJECT(gtkblist->text_rend), "editable", &editable, NULL); | |
2839 if (editable) | |
2840 return FALSE; | |
2841 | |
2842 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y + (gtkblist->tip_rect.height/2), | |
2843 &path, NULL, NULL, NULL)) | |
2844 return FALSE; | |
2845 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
2846 val.g_type = 0; | |
2847 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
2848 node = g_value_get_pointer(&val); | |
2849 | |
2850 pidgin_blist_draw_tooltip(node, gtkblist->window); | |
2851 | |
2852 gtk_tree_path_free(path); | |
2853 return FALSE; | |
2854 } | |
2855 | |
2856 void pidgin_blist_draw_tooltip(PurpleBlistNode *node, GtkWidget *widget) | |
2857 { | |
2858 int scr_w, scr_h, w, h, x, y; | |
2859 #if GTK_CHECK_VERSION(2,2,0) | |
2860 int mon_num; | |
2861 GdkScreen *screen = NULL; | |
2862 #endif | |
2863 gboolean tooltip_top = FALSE; | |
2864 struct _pidgin_blist_node *gtknode; | |
2865 GdkRectangle mon_size; | |
2866 int sig; | |
2867 const char *name; | |
2868 | |
2869 if (node == NULL) | |
2870 return; | |
2871 | |
2872 /* | |
2873 * Attempt to free the previous tooltip. I have a feeling | |
2874 * this is never needed... but just in case. | |
2875 */ | |
2876 pidgin_blist_tooltip_destroy(); | |
2877 | |
2878 gtkblist->tipwindow = gtk_window_new(GTK_WINDOW_POPUP); | |
2879 | |
2880 if(PURPLE_BLIST_NODE_IS_CHAT(node) || PURPLE_BLIST_NODE_IS_BUDDY(node)) { | 2780 if(PURPLE_BLIST_NODE_IS_CHAT(node) || PURPLE_BLIST_NODE_IS_BUDDY(node)) { |
2881 struct tooltip_data *td = create_tip_for_node(node, TRUE); | 2781 struct tooltip_data *td = create_tip_for_node(node, TRUE); |
2882 gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); | 2782 gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); |
2883 w = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + | 2783 width = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + |
2884 MAX(td->width, td->name_width) + SMALL_SPACE + td->avatar_width + TOOLTIP_BORDER; | 2784 MAX(td->width, td->name_width) + SMALL_SPACE + td->avatar_width + TOOLTIP_BORDER; |
2885 h = TOOLTIP_BORDER + MAX(td->height + td->name_height, MAX(STATUS_SIZE, td->avatar_height)) | 2785 height = TOOLTIP_BORDER + MAX(td->height + td->name_height, MAX(STATUS_SIZE, td->avatar_height)) |
2886 + TOOLTIP_BORDER; | 2786 + TOOLTIP_BORDER; |
2887 } else if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { | 2787 } else if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { |
2888 PurpleBlistNode *child; | 2788 PurpleBlistNode *child; |
2889 PurpleBuddy *b = purple_contact_get_priority_buddy((PurpleContact *)node); | 2789 PurpleBuddy *b = purple_contact_get_priority_buddy((PurpleContact *)node); |
2890 int max_text_width = 0; | 2790 int max_text_width = 0; |
2891 int max_avatar_width = 0; | 2791 int max_avatar_width = 0; |
2892 w = h = 0; | 2792 width = height = 0; |
2893 | 2793 |
2894 for(child = node->child; child; child = child->next) | 2794 for(child = node->child; child; child = child->next) |
2895 { | 2795 { |
2896 if(PURPLE_BLIST_NODE_IS_BUDDY(child) && buddy_is_displayable((PurpleBuddy*)child)) { | 2796 if(PURPLE_BLIST_NODE_IS_BUDDY(child) && buddy_is_displayable((PurpleBuddy*)child)) { |
2897 struct tooltip_data *td = create_tip_for_node(child, (b == (PurpleBuddy*)child)); | 2797 struct tooltip_data *td = create_tip_for_node(child, (b == (PurpleBuddy*)child)); |
2900 } else { | 2800 } else { |
2901 gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); | 2801 gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); |
2902 } | 2802 } |
2903 max_text_width = MAX(max_text_width, MAX(td->width, td->name_width)); | 2803 max_text_width = MAX(max_text_width, MAX(td->width, td->name_width)); |
2904 max_avatar_width = MAX(max_avatar_width, td->avatar_width); | 2804 max_avatar_width = MAX(max_avatar_width, td->avatar_width); |
2905 h += MAX(TOOLTIP_BORDER + MAX(STATUS_SIZE,td->avatar_height), | 2805 height += MAX(TOOLTIP_BORDER + MAX(STATUS_SIZE,td->avatar_height), |
2906 TOOLTIP_BORDER + td->height + td->name_height); | 2806 TOOLTIP_BORDER + td->height + td->name_height); |
2907 } | 2807 } |
2908 } | 2808 } |
2909 h += TOOLTIP_BORDER; | 2809 height += TOOLTIP_BORDER; |
2910 w = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + max_text_width + SMALL_SPACE + max_avatar_width + TOOLTIP_BORDER; | 2810 width = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + max_text_width + SMALL_SPACE + max_avatar_width + TOOLTIP_BORDER; |
2911 } else { | 2811 } else { |
2912 gtk_widget_destroy(gtkblist->tipwindow); | 2812 return FALSE; |
2913 gtkblist->tipwindow = NULL; | 2813 } |
2914 return; | 2814 |
2915 } | 2815 if (w) |
2916 | 2816 *w = width; |
2917 if (gtkblist->tooltipdata == NULL) { | 2817 if (h) |
2918 gtk_widget_destroy(gtkblist->tipwindow); | 2818 *h = height; |
2919 gtkblist->tipwindow = NULL; | 2819 |
2920 return; | 2820 return TRUE; |
2821 } | |
2822 | |
2823 static gboolean pidgin_blist_expand_timeout(GtkWidget *tv) | |
2824 { | |
2825 GtkTreePath *path; | |
2826 GtkTreeIter iter; | |
2827 PurpleBlistNode *node; | |
2828 GValue val; | |
2829 struct _pidgin_blist_node *gtknode; | |
2830 | |
2831 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y + (gtkblist->tip_rect.height/2), | |
2832 &path, NULL, NULL, NULL)) | |
2833 return FALSE; | |
2834 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
2835 val.g_type = 0; | |
2836 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
2837 node = g_value_get_pointer(&val); | |
2838 | |
2839 if(!PURPLE_BLIST_NODE_IS_CONTACT(node)) { | |
2840 gtk_tree_path_free(path); | |
2841 return FALSE; | |
2921 } | 2842 } |
2922 | 2843 |
2923 gtknode = node->ui_data; | 2844 gtknode = node->ui_data; |
2924 | 2845 |
2925 name = gtk_window_get_title(GTK_WINDOW(gtk_widget_get_toplevel(widget))); | 2846 if (!gtknode->contact_expanded) { |
2926 gtk_widget_set_app_paintable(gtkblist->tipwindow, TRUE); | 2847 GtkTreeIter i; |
2927 gtk_window_set_title(GTK_WINDOW(gtkblist->tipwindow), name ? name : _("Buddy List")); | 2848 |
2928 gtk_window_set_resizable(GTK_WINDOW(gtkblist->tipwindow), FALSE); | 2849 pidgin_blist_expand_contact_cb(NULL, node); |
2929 gtk_widget_set_name(gtkblist->tipwindow, "gtk-tooltips"); | 2850 |
2930 g_signal_connect(G_OBJECT(gtkblist->tipwindow), "expose_event", | 2851 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, >kblist->contact_rect); |
2931 G_CALLBACK(pidgin_blist_paint_tip), NULL); | 2852 gdk_drawable_get_size(GDK_DRAWABLE(tv->window), &(gtkblist->contact_rect.width), NULL); |
2932 gtk_widget_ensure_style (gtkblist->tipwindow); | 2853 gtkblist->mouseover_contact = node; |
2933 | 2854 gtk_tree_path_down (path); |
2934 #if GTK_CHECK_VERSION(2,2,0) | 2855 while (gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &i, path)) { |
2935 gdk_display_get_pointer(gdk_display_get_default(), &screen, &x, &y, NULL); | 2856 GdkRectangle rect; |
2936 mon_num = gdk_screen_get_monitor_at_point(screen, x, y); | 2857 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect); |
2937 gdk_screen_get_monitor_geometry(screen, mon_num, &mon_size); | 2858 gtkblist->contact_rect.height += rect.height; |
2938 | 2859 gtk_tree_path_next(path); |
2939 scr_w = mon_size.width + mon_size.x; | 2860 } |
2940 scr_h = mon_size.height + mon_size.y; | 2861 } |
2941 #else | 2862 gtk_tree_path_free(path); |
2942 scr_w = gdk_screen_width(); | 2863 return FALSE; |
2943 scr_h = gdk_screen_height(); | 2864 } |
2944 gdk_window_get_pointer(NULL, &x, &y, NULL); | 2865 |
2945 mon_size.x = 0; | 2866 static gboolean buddy_is_displayable(PurpleBuddy *buddy) |
2946 mon_size.y = 0; | 2867 { |
2947 #endif | 2868 struct _pidgin_blist_node *gtknode; |
2948 | 2869 |
2949 #if GTK_CHECK_VERSION(2,2,0) | 2870 if(!buddy) |
2950 if (w > mon_size.width) | 2871 return FALSE; |
2951 w = mon_size.width - 10; | 2872 |
2952 | 2873 gtknode = ((PurpleBlistNode*)buddy)->ui_data; |
2953 if (h > mon_size.height) | 2874 |
2954 h = mon_size.height - 10; | 2875 return (purple_account_is_connected(buddy->account) && |
2955 #endif | 2876 (purple_presence_is_online(buddy->presence) || |
2956 | 2877 (gtknode && gtknode->recent_signonoff) || |
2957 x -= ((w >> 1) + 4); | 2878 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies") || |
2958 | 2879 purple_blist_node_get_bool((PurpleBlistNode*)buddy, "show_offline"))); |
2959 if ((y + h + 4) > scr_h || tooltip_top) | 2880 } |
2960 y = y - h - 5; | 2881 |
2961 else | 2882 void pidgin_blist_draw_tooltip(PurpleBlistNode *node, GtkWidget *widget) |
2962 y = y + 6; | 2883 { |
2963 | 2884 pidgin_tooltip_show(widget, node, pidgin_blist_create_tooltip_for_node, pidgin_blist_paint_tip); |
2964 if (y < mon_size.y) | |
2965 y = mon_size.y; | |
2966 | |
2967 if (y != mon_size.y) { | |
2968 if ((x + w) > scr_w) | |
2969 x -= (x + w + 5) - scr_w; | |
2970 else if (x < mon_size.x) | |
2971 x = mon_size.x; | |
2972 } else { | |
2973 x -= (w / 2 + 10); | |
2974 if (x < mon_size.x) | |
2975 x = mon_size.x; | |
2976 } | |
2977 | |
2978 gtk_widget_set_size_request(gtkblist->tipwindow, w, h); | |
2979 gtk_window_move(GTK_WINDOW(gtkblist->tipwindow), x, y); | |
2980 gtk_widget_show(gtkblist->tipwindow); | |
2981 | |
2982 /* Hide the tooltip when the widget is destroyed */ | |
2983 sig = g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(pidgin_blist_tooltip_destroy), NULL); | |
2984 g_signal_connect_swapped(G_OBJECT(gtkblist->tipwindow), "destroy", G_CALLBACK(g_source_remove), GINT_TO_POINTER(sig)); | |
2985 | |
2986 return; | |
2987 } | 2885 } |
2988 | 2886 |
2989 static gboolean pidgin_blist_drag_motion_cb(GtkWidget *tv, GdkDragContext *drag_context, | 2887 static gboolean pidgin_blist_drag_motion_cb(GtkWidget *tv, GdkDragContext *drag_context, |
2990 gint x, gint y, guint time, gpointer user_data) | 2888 gint x, gint y, guint time, gpointer user_data) |
2991 { | 2889 { |
3031 } | 2929 } |
3032 | 2930 |
3033 return FALSE; | 2931 return FALSE; |
3034 } | 2932 } |
3035 | 2933 |
2934 static gboolean | |
2935 pidgin_blist_create_tooltip(GtkWidget *widget, GtkTreePath *path, | |
2936 gpointer null, int *w, int *h) | |
2937 { | |
2938 GtkTreeIter iter; | |
2939 PurpleBlistNode *node; | |
2940 GValue val; | |
2941 gboolean editable = FALSE; | |
2942 | |
2943 /* If we're editing a cell (e.g. alias editing), don't show the tooltip */ | |
2944 g_object_get(G_OBJECT(gtkblist->text_rend), "editable", &editable, NULL); | |
2945 if (editable) | |
2946 return FALSE; | |
2947 | |
2948 if (gtkblist->tooltipdata) { | |
2949 gtkblist->tipwindow = NULL; | |
2950 pidgin_blist_destroy_tooltip_data(); | |
2951 } | |
2952 | |
2953 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
2954 val.g_type = 0; | |
2955 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
2956 node = g_value_get_pointer(&val); | |
2957 return pidgin_blist_create_tooltip_for_node(widget, node, w, h); | |
2958 } | |
2959 | |
3036 static gboolean pidgin_blist_motion_cb (GtkWidget *tv, GdkEventMotion *event, gpointer null) | 2960 static gboolean pidgin_blist_motion_cb (GtkWidget *tv, GdkEventMotion *event, gpointer null) |
3037 { | 2961 { |
3038 GtkTreePath *path; | |
3039 int delay; | |
3040 | |
3041 delay = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay"); | |
3042 | |
3043 if (delay == 0) | |
3044 return FALSE; | |
3045 | |
3046 if (gtkblist->timeout) { | |
3047 if ((event->y > gtkblist->tip_rect.y) && ((event->y - gtkblist->tip_rect.height) < gtkblist->tip_rect.y)) | |
3048 return FALSE; | |
3049 /* We've left the cell. Remove the timeout and create a new one below */ | |
3050 pidgin_blist_tooltip_destroy(); | |
3051 g_source_remove(gtkblist->timeout); | |
3052 } | |
3053 | |
3054 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL); | |
3055 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, >kblist->tip_rect); | |
3056 | |
3057 if (path) | |
3058 gtk_tree_path_free(path); | |
3059 gtkblist->timeout = g_timeout_add(delay, (GSourceFunc)pidgin_blist_tooltip_timeout, tv); | |
3060 | |
3061 if (gtkblist->mouseover_contact) { | 2962 if (gtkblist->mouseover_contact) { |
3062 if ((event->y < gtkblist->contact_rect.y) || ((event->y - gtkblist->contact_rect.height) > gtkblist->contact_rect.y)) { | 2963 if ((event->y < gtkblist->contact_rect.y) || ((event->y - gtkblist->contact_rect.height) > gtkblist->contact_rect.y)) { |
3063 pidgin_blist_collapse_contact_cb(NULL, gtkblist->mouseover_contact); | 2964 pidgin_blist_collapse_contact_cb(NULL, gtkblist->mouseover_contact); |
3064 gtkblist->mouseover_contact = NULL; | 2965 gtkblist->mouseover_contact = NULL; |
3065 } | 2966 } |
3068 return FALSE; | 2969 return FALSE; |
3069 } | 2970 } |
3070 | 2971 |
3071 static void pidgin_blist_leave_cb (GtkWidget *w, GdkEventCrossing *e, gpointer n) | 2972 static void pidgin_blist_leave_cb (GtkWidget *w, GdkEventCrossing *e, gpointer n) |
3072 { | 2973 { |
3073 | |
3074 if (gtkblist->timeout) { | 2974 if (gtkblist->timeout) { |
3075 g_source_remove(gtkblist->timeout); | 2975 g_source_remove(gtkblist->timeout); |
3076 gtkblist->timeout = 0; | 2976 gtkblist->timeout = 0; |
3077 } | 2977 } |
3078 | 2978 |
3079 if (gtkblist->drag_timeout) { | 2979 if (gtkblist->drag_timeout) { |
3080 g_source_remove(gtkblist->drag_timeout); | 2980 g_source_remove(gtkblist->drag_timeout); |
3081 gtkblist->drag_timeout = 0; | 2981 gtkblist->drag_timeout = 0; |
3082 } | 2982 } |
3083 | |
3084 pidgin_blist_tooltip_destroy(); | |
3085 | 2983 |
3086 if (gtkblist->mouseover_contact && | 2984 if (gtkblist->mouseover_contact && |
3087 !((e->x > gtkblist->contact_rect.x) && (e->x < (gtkblist->contact_rect.x + gtkblist->contact_rect.width)) && | 2985 !((e->x > gtkblist->contact_rect.x) && (e->x < (gtkblist->contact_rect.x + gtkblist->contact_rect.width)) && |
3088 (e->y > gtkblist->contact_rect.y) && (e->y < (gtkblist->contact_rect.y + gtkblist->contact_rect.height)))) { | 2986 (e->y > gtkblist->contact_rect.y) && (e->y < (gtkblist->contact_rect.y + gtkblist->contact_rect.height)))) { |
3089 pidgin_blist_collapse_contact_cb(NULL, gtkblist->mouseover_contact); | 2987 pidgin_blist_collapse_contact_cb(NULL, gtkblist->mouseover_contact); |
5150 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-received", G_CALLBACK(pidgin_blist_drag_data_rcv_cb), NULL); | 5048 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-received", G_CALLBACK(pidgin_blist_drag_data_rcv_cb), NULL); |
5151 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-get", G_CALLBACK(pidgin_blist_drag_data_get_cb), NULL); | 5049 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-get", G_CALLBACK(pidgin_blist_drag_data_get_cb), NULL); |
5152 #ifdef _WIN32 | 5050 #ifdef _WIN32 |
5153 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-begin", G_CALLBACK(pidgin_blist_drag_begin), NULL); | 5051 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-begin", G_CALLBACK(pidgin_blist_drag_begin), NULL); |
5154 #endif | 5052 #endif |
5155 | |
5156 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-motion", G_CALLBACK(pidgin_blist_drag_motion_cb), NULL); | 5053 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-motion", G_CALLBACK(pidgin_blist_drag_motion_cb), NULL); |
5157 | |
5158 /* Tooltips */ | |
5159 g_signal_connect(G_OBJECT(gtkblist->treeview), "motion-notify-event", G_CALLBACK(pidgin_blist_motion_cb), NULL); | 5054 g_signal_connect(G_OBJECT(gtkblist->treeview), "motion-notify-event", G_CALLBACK(pidgin_blist_motion_cb), NULL); |
5160 g_signal_connect(G_OBJECT(gtkblist->treeview), "leave-notify-event", G_CALLBACK(pidgin_blist_leave_cb), NULL); | 5055 g_signal_connect(G_OBJECT(gtkblist->treeview), "leave-notify-event", G_CALLBACK(pidgin_blist_leave_cb), NULL); |
5056 | |
5057 /* Tooltips */ | |
5058 pidgin_tooltip_setup_for_treeview(gtkblist->treeview, NULL, | |
5059 pidgin_blist_create_tooltip, | |
5060 pidgin_blist_paint_tip); | |
5161 | 5061 |
5162 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE); | 5062 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE); |
5163 | 5063 |
5164 column = gtk_tree_view_column_new(); | 5064 column = gtk_tree_view_column_new(); |
5165 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | 5065 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); |