# HG changeset patch # User Sadrul Habib Chowdhury # Date 1153171418 0 # Node ID 6741419af7f75abe6890755fca1b7b278b92b071 # Parent 421259b9e06d104a63f3791fb91300a4a624979f [gaim-migrate @ 16510] Add a context menu for the buddy-list. Most of the menus don't do anything yet, because the request-ui is not done. But the others, eg. 'Get Info', 'Join In Chat' etc.) work. committer: Tailor Script diff -r 421259b9e06d -r 6741419af7f7 console/gntblist.c --- a/console/gntblist.c Mon Jul 17 13:37:08 2006 +0000 +++ b/console/gntblist.c Mon Jul 17 21:23:38 2006 +0000 @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -19,6 +20,9 @@ GntWidget *tooltip; GaimBlistNode *tnode; /* Who is the tooltip being displayed for? */ + + GntWidget *context; + GaimBlistNode *cnode; } GGBlist; GGBlist *ggblist; @@ -28,6 +32,7 @@ static void add_chat(GaimChat *chat, GGBlist *ggblist); static void add_node(GaimBlistNode *node, GGBlist *ggblist); static void draw_tooltip(GGBlist *ggblist); +static void remove_peripherals(GGBlist *ggblist); static void new_node(GaimBlistNode *node) @@ -252,6 +257,231 @@ } static void +remove_context_menu(GGBlist *ggblist) +{ + if (ggblist->context) + gnt_widget_destroy(ggblist->context->parent); + ggblist->context = NULL; + ggblist->cnode = NULL; +} + +static void +gnt_append_menu_action(GntTree *tree, GaimMenuAction *action, gpointer parent) +{ + GList *list; + + gnt_tree_add_row_after(tree, action, action->label, parent, NULL); + for (list = action->children; list; list = list->next) + gnt_append_menu_action(tree, list->data, action); +} + +static void +append_proto_menu(GntTree *tree, GaimConnection *gc, GaimBlistNode *node) +{ + GList *list; + GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); + + if(!prpl_info || !prpl_info->blist_node_menu) + return; + + for(list = prpl_info->blist_node_menu(node); list; + list = g_list_delete_link(list, list)) + { + GaimMenuAction *act = (GaimMenuAction *) list->data; + gnt_append_menu_action(tree, act, NULL); + } +} + +static void +add_custom_action(GntTree *tree, const char *label, GaimCallback callback, + gpointer data) +{ + GaimMenuAction *action = gaim_menu_action_new(label, callback, data, NULL); + gnt_append_menu_action(tree, action, NULL); + g_signal_connect_swapped(G_OBJECT(tree), "destroy", + G_CALLBACK(gaim_menu_action_free), action); +} + +static void +create_chat_menu(GntTree *tree, GaimChat *chat) +{ +} + +static void +create_group_menu(GntTree *tree, GaimGroup *group) +{ +} + +static void +gg_blist_get_buddy_info_cb(GaimBuddy *buddy, GaimBlistNode *null) +{ + serv_get_info(buddy->account->gc, gaim_buddy_get_name(buddy)); +} + +static void +create_buddy_menu(GntTree *tree, GaimBuddy *buddy) +{ + GaimPluginProtocolInfo *prpl_info; + + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl); + if (prpl_info && prpl_info->get_info) + { + add_custom_action(tree, _("Get Info"), + GAIM_CALLBACK(gg_blist_get_buddy_info_cb), buddy); + } + +#if 0 + add_custom_action(tree, _("Add Buddy Pounce"), + GAIM_CALLBACK(gg_blist_add_buddy_pounce_cb)), buddy); + + if (prpl_info && prpl_info->send_file) + { + if (!prpl_info->can_receive_file || + prpl_info->can_receive_file(buddy->account->gc, buddy->name)) + add_custom_action(tree, _("Send File"), + GAIM_CALLBACK(gg_blist_show_file_cb)), buddy); + } + + add_custom_action(tree, _("View Log"), + GAIM_CALLBACK(gg_blist_view_log_cb)), buddy); +#endif + + /* Protocol actions */ + append_proto_menu(tree, + gaim_account_get_connection(gaim_buddy_get_account(buddy)), + (GaimBlistNode*)buddy); +} + +static void +append_extended_menu(GntTree *tree, GaimBlistNode *node) +{ + GList *iter; + + for (iter = gaim_blist_node_get_extended_menu(node); + iter; iter = g_list_delete_link(iter, iter)) + { + gnt_append_menu_action(tree, iter->data, NULL); + } +} + +static void +context_menu_callback(GntTree *tree, GGBlist *ggblist) +{ + GaimMenuAction *action = gnt_tree_get_selection_data(tree); + GaimBlistNode *node = ggblist->cnode; + + if (action) + { + void (*callback)(GaimBlistNode *, gpointer); + callback = (void (*)(GaimBlistNode *, gpointer))action->callback; + callback(node, action->data); + } + + remove_context_menu(ggblist); +} + +static void +gg_blist_rename_node_cb(GaimBlistNode *node, GaimBlistNode *null) +{ +} + +/* XXX: This still doesn't do anything, because request doesn't have a ui yet */ +static void +gg_blist_remove_node_cb(GaimBlistNode *node, GaimBlistNode *null) +{ + void (*callback)(gpointer); + + if (GAIM_BLIST_NODE_IS_BUDDY(node)) + callback = (void(*)(gpointer))gaim_blist_remove_buddy; + else if (GAIM_BLIST_NODE_IS_CHAT(node)) + callback = (void(*)(gpointer))gaim_blist_remove_chat; + else if (GAIM_BLIST_NODE_IS_GROUP(node)) + callback = (void(*)(gpointer))gaim_blist_remove_group; + + /* XXX: anything to do with the returned ui-handle? */ + gaim_request_action(node, _("Confirm Remove"), + _("Are you sure you want to remove ..."), NULL, /* XXX: tidy up */ + 1, node, 2, + _("Remove"), callback, + _("No"), NULL); + +} + +static void +draw_context_menu(GGBlist *ggblist) +{ + GaimBlistNode *node = NULL; + GntWidget *context = NULL, *window = NULL; + GntTree *tree = NULL; + int x, y, top, width; + char *title = NULL; + + tree = GNT_TREE(ggblist->tree); + + if (ggblist->context) + { + remove_context_menu(ggblist); + } + + node = gnt_tree_get_selection_data(tree); + + if (node == NULL) + return; + if (ggblist->tooltip) + remove_tooltip(ggblist); + + ggblist->cnode = node; + ggblist->context = context = gnt_tree_new(); + GNT_WIDGET_SET_FLAGS(context, GNT_WIDGET_NO_BORDER); + gnt_widget_set_name(context, "context menu"); + g_signal_connect(G_OBJECT(context), "activate", G_CALLBACK(context_menu_callback), ggblist); + + if (GAIM_BLIST_NODE_IS_BUDDY(node)) + { + GaimBuddy *buddy = (GaimBuddy *)node; + create_buddy_menu(GNT_TREE(context), buddy); + title = g_strdup(gaim_buddy_get_name(buddy)); + } + else if (GAIM_BLIST_NODE_IS_CHAT(node)) + { + GaimChat *chat = (GaimChat*)node; + create_chat_menu(GNT_TREE(context), chat); + title = g_strdup(gaim_chat_get_name(chat)); + } + else if (GAIM_BLIST_NODE_IS_GROUP(node)) + { + GaimGroup *group = (GaimGroup *)node; + create_group_menu(GNT_TREE(context), group); + title = g_strdup(group->name); + } + + append_extended_menu(GNT_TREE(context), node); + + /* These are common for everything */ + add_custom_action(GNT_TREE(context), _("Rename"), + GAIM_CALLBACK(gg_blist_rename_node_cb), node); + add_custom_action(GNT_TREE(context), _("Remove"), + GAIM_CALLBACK(gg_blist_remove_node_cb), node); + + window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), title); + + gnt_box_add_widget(GNT_BOX(window), context); + + /* Set the position for the popup */ + gnt_widget_get_position(GNT_WIDGET(tree), &x, &y); + gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL); + top = gnt_tree_get_selection_visible_line(tree); + + x += width; + y += top - 1; + + gnt_widget_set_position(window, x, y); + gnt_widget_draw(window); +} + +static void draw_tooltip(GGBlist *ggblist) { GaimBlistNode *node; @@ -270,6 +500,9 @@ if (!gnt_widget_has_focus(ggblist->tree)) return; + if (ggblist->context) + return; + if (ggblist->tooltip) { /* XXX: Once we can properly redraw on expose events, this can be removed at the end @@ -372,18 +605,35 @@ static gboolean key_pressed(GntWidget *widget, const char *text, GGBlist *ggblist) { + gboolean stop = FALSE, ret = FALSE; if (text[0] == 27 && text[1] == 0) { /* Escape was pressed */ - if (ggblist->tooltip) + remove_peripherals(ggblist); + stop = TRUE; + ret = TRUE; + } + + if (ggblist->context) + { + ret = gnt_widget_key_pressed(ggblist->context, text); + stop = TRUE; + } + + if (text[0] == 27) + { + if (strcmp(text + 1, GNT_KEY_POPUP) == 0) { - gnt_widget_destroy(ggblist->tooltip); - ggblist->tooltip = NULL; - return TRUE; + draw_context_menu(ggblist); + stop = TRUE; + ret = TRUE; } } - return FALSE; + if (stop) + g_signal_stop_emission_by_name(G_OBJECT(widget), "key_pressed"); + + return ret; } static void @@ -411,6 +661,15 @@ update_buddy_display(buddy, ggblist); } +static void +remove_peripherals(GGBlist *ggblist) +{ + if (ggblist->tooltip) + remove_tooltip(ggblist); + else if (ggblist->context) + remove_context_menu(ggblist); +} + void gg_blist_init() { ggblist = g_new0(GGBlist, 1); @@ -456,7 +715,7 @@ g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist); g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip), ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); - g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_tooltip), + g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_peripherals), ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); }