# HG changeset patch # User Sean Egan # Date 1185599288 0 # Node ID 30b6f8bc47cf67eaa97a2a3d524105b207aecad1 # Parent 70c758256110fd9fa0bd9fe0750a1dfb82c7c7e6 Tooltips in infopanes diff -r 70c758256110 -r 30b6f8bc47cf ChangeLog.API --- a/ChangeLog.API Sat Jul 28 04:27:18 2007 +0000 +++ b/ChangeLog.API Sat Jul 28 05:08:08 2007 +0000 @@ -74,6 +74,8 @@ * pidgin_menu_position_func_helper * pidgin_blist_get_name_markup, returns the buddy list markup text for a given buddy. + * pidgin_blist_draw_tooltip and pidgin_blist_tooltip_destroy + for creating blist tooltips from outside of buddy list code * pidgin_themes_remove_smiley_theme Changed: diff -r 70c758256110 -r 30b6f8bc47cf pidgin/gtkblist.c --- a/pidgin/gtkblist.c Sat Jul 28 04:27:18 2007 +0000 +++ b/pidgin/gtkblist.c Sat Jul 28 05:08:08 2007 +0000 @@ -136,8 +136,6 @@ static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node); static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded); -static void pidgin_blist_tooltip_destroy(void); - struct _pidgin_blist_node { GtkTreeRowReference *row; gboolean contact_expanded; @@ -1150,7 +1148,8 @@ pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce"), NULL, G_CALLBACK(gtk_blist_menu_bp_cb), buddy, 0, 0, NULL); - if(((PurpleBlistNode*)buddy)->parent->child->next && !sub && !contact_expanded) { + if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && + !sub && !contact_expanded) { pidgin_new_item_from_stock(menu, _("View _Log"), NULL, G_CALLBACK(gtk_blist_menu_showlog_cb), contact, 0, 0, NULL); @@ -1164,7 +1163,8 @@ (PurpleBlistNode *)buddy); pidgin_append_blist_node_extended_menu(menu, (PurpleBlistNode *)buddy); - if (((PurpleBlistNode*)buddy)->parent->child->next && !sub && !contact_expanded) { + if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && + !sub && !contact_expanded) { pidgin_separator(menu); pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy); pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, @@ -2496,7 +2496,7 @@ } -static void pidgin_blist_tooltip_destroy() +void pidgin_blist_tooltip_destroy() { while(gtkblist->tooltipdata) { struct tooltip_data *td = gtkblist->tooltipdata->data; @@ -2584,6 +2584,22 @@ GtkTreeIter iter; PurpleBlistNode *node; GValue val; + + if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y, &path, NULL, NULL, NULL)) + return FALSE; + gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); + val.g_type = 0; + gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); + node = g_value_get_pointer(&val); + + pidgin_blist_draw_tooltip(node, gtkblist->window); + + gtk_tree_path_free(path); + return FALSE; +} + +void pidgin_blist_draw_tooltip(PurpleBlistNode *node, GtkWidget *widget) +{ int scr_w, scr_h, w, h, x, y; #if GTK_CHECK_VERSION(2,2,0) int mon_num; @@ -2592,6 +2608,9 @@ gboolean tooltip_top = FALSE; struct _pidgin_blist_node *gtknode; GdkRectangle mon_size; + + if (node == NULL) + return; /* * Attempt to free the previous tooltip. I have a feeling @@ -2599,14 +2618,6 @@ */ pidgin_blist_tooltip_destroy(); - if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y, &path, NULL, NULL, NULL)) - return FALSE; - gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); - val.g_type = 0; - gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); - node = g_value_get_pointer(&val); - - gtk_tree_path_free(path); gtkblist->tipwindow = gtk_window_new(GTK_WINDOW_POPUP); @@ -2644,13 +2655,13 @@ } else { gtk_widget_destroy(gtkblist->tipwindow); gtkblist->tipwindow = NULL; - return FALSE; + return; } if (gtkblist->tooltipdata == NULL) { gtk_widget_destroy(gtkblist->tipwindow); gtkblist->tipwindow = NULL; - return FALSE; + return; } gtknode = node->ui_data; @@ -2686,9 +2697,6 @@ h = mon_size.height - 10; #endif - if (GTK_WIDGET_NO_WINDOW(gtkblist->window)) - y+=gtkblist->window->allocation.y; - x -= ((w >> 1) + 4); if ((y + h + 4) > scr_h || tooltip_top) @@ -2714,7 +2722,7 @@ gtk_window_move(GTK_WINDOW(gtkblist->tipwindow), x, y); gtk_widget_show(gtkblist->tipwindow); - return FALSE; + return; } static gboolean pidgin_blist_drag_motion_cb(GtkWidget *tv, GdkDragContext *drag_context, diff -r 70c758256110 -r 30b6f8bc47cf pidgin/gtkblist.h --- a/pidgin/gtkblist.h Sat Jul 28 04:27:18 2007 +0000 +++ b/pidgin/gtkblist.h Sat Jul 28 05:08:08 2007 +0000 @@ -370,4 +370,21 @@ */ gchar *pidgin_blist_get_name_markup(PurpleBuddy *buddy, gboolean selected, gboolean aliased); +/** + * Creates the Buddy List tooltip at the current pointer location for the given buddy list node. + * + * This tooltip will be destroyed the next time this function is called, or when XXXX + * is called + * + * @param buddy The buddy to show a tooltip for + * @param widget The widget to draw the tooltip on + */ +void pidgin_blist_draw_tooltip(PurpleBlistNode *node, GtkWidget *widget); + +/** + * Destroys the current (if any) Buddy List tooltip + */ +void pidgin_blist_tooltip_destroy(void); + + #endif /* _PIDGINBLIST_H_ */ diff -r 70c758256110 -r 30b6f8bc47cf pidgin/gtkconv.c --- a/pidgin/gtkconv.c Sat Jul 28 04:27:18 2007 +0000 +++ b/pidgin/gtkconv.c Sat Jul 28 05:08:08 2007 +0000 @@ -4408,6 +4408,50 @@ gtk_container_add(GTK_CONTAINER(sw), list); } +static int tooltip_timeout = 0; + +static gboolean +pidgin_conv_tooltip_timeout(PidginConversation *gtkconv) +{ + PurpleBlistNode *node = NULL; + PurpleConversation *conv = gtkconv->active_conv; + if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { + node = (PurpleBlistNode*)(purple_blist_find_chat(conv->account, conv->name)); + } else { + node = (PurpleBlistNode*)(purple_find_buddy(conv->account, conv->name)); + } + + if (node) + pidgin_blist_draw_tooltip(node, gtkconv->infopane); + return FALSE; +} + +static void +pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv) +{ + pidgin_blist_tooltip_destroy(); + if (tooltip_timeout) { + g_source_remove(tooltip_timeout); + tooltip_timeout = 0; + } +} + +static gboolean +pidgin_conv_motion_cb (GtkWidget *infopane, GdkEventMotion *event, PidginConversation *gtkconv) +{ + int delay = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay"); + + pidgin_blist_tooltip_destroy(); + if (delay == 0) + return FALSE; + + if (tooltip_timeout != 0) + g_source_remove(tooltip_timeout); + + tooltip_timeout = g_timeout_add(delay, (GSourceFunc)pidgin_conv_tooltip_timeout, gtkconv); + return FALSE; +} + static GtkWidget * setup_common_pane(PidginConversation *gtkconv) { @@ -4437,10 +4481,15 @@ gtk_container_add(GTK_CONTAINER(event_box), gtkconv->infopane_hbox); gtk_widget_show(gtkconv->infopane_hbox); gtk_widget_add_events(event_box, - GDK_BUTTON1_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); + GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(infopane_press_cb), gtkconv); + g_signal_connect(G_OBJECT(event_box), "motion-notify-event", + G_CALLBACK(pidgin_conv_motion_cb), gtkconv); + g_signal_connect(G_OBJECT(event_box), "leave-notify-event", + G_CALLBACK(pidgin_conv_leave_cb), gtkconv); + gtkconv->infopane = gtk_cell_view_new(); gtkconv->infopane_model = gtk_list_store_new(CONV_NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDK_TYPE_PIXBUF); @@ -7660,8 +7709,6 @@ static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *gtkconv) { - int nb_x, nb_y; - if (e->type != GDK_BUTTON_PRESS) return FALSE; @@ -7692,39 +7739,10 @@ gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, e->button, e->time); return TRUE; - } else if (e->button != 1) { - return FALSE; - } - - if (gtkconv->win->in_drag) { - purple_debug(PURPLE_DEBUG_WARNING, "gtkconv", - "Already in the middle of a window drag at tab_press_cb\n"); - return TRUE; - } - - gtkconv->win->in_predrag = TRUE; - gtkconv->win->drag_tab = gtk_notebook_page_num(GTK_NOTEBOOK(gtkconv->win->notebook), gtkconv->tab_cont); - - gdk_window_get_origin(gtkconv->infopane_hbox->window, &nb_x, &nb_y); - - gtkconv->win->drag_min_x = gtkconv->infopane_hbox->allocation.x + nb_x; - gtkconv->win->drag_min_y = gtkconv->infopane_hbox->allocation.y + nb_y; - gtkconv->win->drag_max_x = gtkconv->infopane_hbox->allocation.width + gtkconv->win->drag_min_x; - gtkconv->win->drag_max_y = gtkconv->infopane_hbox->allocation.height + gtkconv->win->drag_min_y; - - /* Connect the new motion signals. */ - gtkconv->win->drag_motion_signal = - g_signal_connect(G_OBJECT(gtkconv->win->notebook), "motion_notify_event", - G_CALLBACK(notebook_motion_cb), gtkconv->win); - - gtkconv->win->drag_leave_signal = - g_signal_connect(G_OBJECT(gtkconv->win->notebook), "leave_notify_event", - G_CALLBACK(notebook_leave_cb), gtkconv->win); - + } return FALSE; - -} - +} + static gboolean notebook_press_cb(GtkWidget *widget, GdkEventButton *e, PidginWindow *win) {