Mercurial > pidgin.yaz
diff finch/gntconv.c @ 17319:8a7238fb7905
explicit merge of 'dc4f2ee34039521ae6a198fe7d62f4dca8a84589'
and '9d8bc74c7c13474edcefafedd0af9020b27c9a2f'
author | Jeffrey Connelly <jaconnel@calpoly.edu> |
---|---|
date | Wed, 30 May 2007 02:56:25 +0000 |
parents | 46f2f86e08e4 |
children | 319bcb73eb4e |
line wrap: on
line diff
--- a/finch/gntconv.c Wed May 23 04:18:05 2007 +0000 +++ b/finch/gntconv.c Wed May 30 02:56:25 2007 +0000 @@ -37,16 +37,29 @@ #include "gntplugin.h" #include "gntprefs.h" #include "gntstatus.h" +#include "gntpounce.h" #include "gnt.h" #include "gntbox.h" #include "gntentry.h" +#include "gntlabel.h" +#include "gntmenu.h" +#include "gntmenuitem.h" +#include "gntmenuitemcheck.h" #include "gnttextview.h" +#include "gnttree.h" +#include "gntutils.h" +#include "gntwindow.h" #define PREF_ROOT "/finch/conversations" +#define PREF_CHAT PREF_ROOT "/chats" +#define PREF_USERLIST PREF_CHAT "/userlist" #include "config.h" +static void finch_write_common(PurpleConversation *conv, const char *who, + const char *message, PurpleMessageFlags flags, time_t mtime); + static void send_typing_notification(GntWidget *w, FinchConv *ggconv) { @@ -258,6 +271,13 @@ g_free(title); } +static void +chat_left_cb(PurpleConversation *conv, gpointer null) +{ + finch_write_common(conv, NULL, _("You have left this chat."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); +} + static gpointer finch_conv_get_handle() { @@ -266,6 +286,165 @@ } static void +clear_scrollback_cb(GntMenuItem *item, gpointer ggconv) +{ + FinchConv *ggc = ggconv; + gnt_text_view_clear(GNT_TEXT_VIEW(ggc->tv)); +} + +static void +send_file_cb(GntMenuItem *item, gpointer ggconv) +{ + FinchConv *ggc = ggconv; + serv_send_file(purple_conversation_get_gc(ggc->active_conv), + purple_conversation_get_name(ggc->active_conv), NULL); +} + +static void +add_pounce_cb(GntMenuItem *item, gpointer ggconv) +{ + FinchConv *ggc = ggconv; + finch_pounce_editor_show( + purple_conversation_get_account(ggc->active_conv), + purple_conversation_get_name(ggc->active_conv), NULL); +} + +static void +get_info_cb(GntMenuItem *item, gpointer ggconv) +{ + FinchConv *ggc = ggconv; + PurpleNotifyUserInfo *info = purple_notify_user_info_new(); + purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving...")); + purple_notify_userinfo(ggc->active_conv->account->gc, purple_conversation_get_name(ggc->active_conv), info, NULL, NULL); + purple_notify_user_info_destroy(info); + + serv_get_info(purple_conversation_get_gc(ggc->active_conv), + purple_conversation_get_name(ggc->active_conv)); +} + +static void +toggle_timestamps_cb(GntMenuItem *item, gpointer ggconv) +{ + purple_prefs_set_bool(PREF_ROOT "/timestamps", + !purple_prefs_get_bool(PREF_ROOT "/timestamps")); +} + +static void +send_to_cb(GntMenuItem *m, gpointer n) +{ + PurpleAccount *account = g_object_get_data(G_OBJECT(m), "purple_account"); + gchar *buddy = g_object_get_data(G_OBJECT(m), "purple_buddy_name"); + PurpleConversation *conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, buddy); + finch_conversation_set_active(conv); +} + +static void +generate_send_to_menu(FinchConv *ggc) +{ + GntWidget *sub, *menu = ggc->menu; + GntMenuItem *item; + GSList *buds; + GList *list = NULL; + + buds = purple_find_buddies(ggc->active_conv->account, ggc->active_conv->name); + if (!buds) + return; + + item = gnt_menuitem_new(_("Send To")); + gnt_menu_add_item(GNT_MENU(menu), item); + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(sub)); + + for (; buds; buds = buds->next) { + PurpleBlistNode *node = (PurpleBlistNode *)purple_buddy_get_contact((PurpleBuddy *)buds->data); + for (node = node->child; node != NULL; node = node->next) { + PurpleBuddy *buddy = (PurpleBuddy *)node; + PurpleAccount *account = purple_buddy_get_account(buddy); + if (purple_account_is_connected(account)) { + /* Use the PurplePresence to get unique buddies. */ + PurplePresence *presence = purple_buddy_get_presence(buddy); + if (!g_list_find(list, presence)) + list = g_list_prepend(list, presence); + } + } + } + for (list = g_list_last(list); list != NULL; list = list->prev) { + PurplePresence *pre = list->data; + PurpleBuddy *buddy = purple_presence_get_buddy(pre); + PurpleAccount *account = purple_buddy_get_account(buddy); + gchar *name = g_strdup(purple_buddy_get_name(buddy)); + gchar *text = g_strdup_printf("%s (%s)", purple_buddy_get_name(buddy), purple_account_get_username(account)); + item = gnt_menuitem_new(text); + g_free(text); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, send_to_cb, NULL); + g_object_set_data(G_OBJECT(item), "purple_account", account); + g_object_set_data_full(G_OBJECT(item), "purple_buddy_name", name, g_free); + } + g_list_free(list); + g_slist_free(buds); +} + +static void +gg_create_menu(FinchConv *ggc) +{ + GntWidget *menu, *sub; + GntMenuItem *item; + + ggc->menu = menu = gnt_menu_new(GNT_MENU_TOPLEVEL); + gnt_window_set_menu(GNT_WINDOW(ggc->window), GNT_MENU(menu)); + + item = gnt_menuitem_new(_("Conversation")); + gnt_menu_add_item(GNT_MENU(menu), item); + + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(sub)); + + item = gnt_menuitem_new(_("Clear Scrollback")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, clear_scrollback_cb, ggc); + + item = gnt_menuitem_check_new(_("Show Timestamps")); + gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), + purple_prefs_get_bool(PREF_ROOT "/timestamps")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, toggle_timestamps_cb, ggc); + + if (purple_conversation_get_type(ggc->active_conv) == PURPLE_CONV_TYPE_IM) { + PurpleAccount *account = purple_conversation_get_account(ggc->active_conv); + PurplePluginProtocolInfo *pinfo = account->gc ? PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl) : NULL; + + if (pinfo && pinfo->get_info) { + item = gnt_menuitem_new(_("Get Info")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, get_info_cb, ggc); + } + + item = gnt_menuitem_new(_("Add Buddy Pounce...")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, add_pounce_cb, ggc); + + if (pinfo && pinfo->send_file && + (!pinfo->can_receive_file || + pinfo->can_receive_file(account->gc, purple_conversation_get_name(ggc->active_conv)))) { + item = gnt_menuitem_new(_("Send File")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, send_file_cb, ggc); + } + + generate_send_to_menu(ggc); + } +} + +static void +create_conv_from_userlist(GntWidget *widget, FinchConv *fc) +{ + PurpleAccount *account = purple_conversation_get_account(fc->active_conv); + char *name = gnt_tree_get_selection_data(GNT_TREE(widget)); + purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name); +} + +static void finch_create_conversation(PurpleConversation *conv) { FinchConv *ggc = conv->ui_data; @@ -296,18 +475,38 @@ type = purple_conversation_get_type(conv); title = get_conversation_title(conv, account); - ggc->window = gnt_box_new(FALSE, TRUE); + ggc->window = gnt_vwindow_new(FALSE); gnt_box_set_title(GNT_BOX(ggc->window), title); gnt_box_set_toplevel(GNT_BOX(ggc->window), TRUE); gnt_box_set_pad(GNT_BOX(ggc->window), 0); gnt_widget_set_name(ggc->window, "conversation-window"); + gg_create_menu(ggc); + ggc->tv = gnt_text_view_new(); - gnt_box_add_widget(GNT_BOX(ggc->window), ggc->tv); gnt_widget_set_name(ggc->tv, "conversation-window-textview"); gnt_widget_set_size(ggc->tv, purple_prefs_get_int(PREF_ROOT "/size/width"), purple_prefs_get_int(PREF_ROOT "/size/height")); + if (type == PURPLE_CONV_TYPE_CHAT) { + GntWidget *hbox, *tree; + FinchConvChat *fc = ggc->u.chat = g_new0(FinchConvChat, 1); + hbox = gnt_hbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(hbox), 0); + tree = fc->userlist = gnt_tree_new_with_columns(2); + gnt_tree_set_col_width(GNT_TREE(tree), 0, 1); /* The flag column */ + gnt_tree_set_compare_func(GNT_TREE(tree), (GCompareFunc)g_utf8_collate); + gnt_tree_set_hash_fns(GNT_TREE(tree), g_str_hash, g_str_equal, g_free); + GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); + gnt_box_add_widget(GNT_BOX(hbox), ggc->tv); + gnt_box_add_widget(GNT_BOX(hbox), tree); + gnt_box_add_widget(GNT_BOX(ggc->window), hbox); + g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(create_conv_from_userlist), ggc); + gnt_widget_set_visible(tree, purple_prefs_get_bool(PREF_USERLIST)); + } else { + gnt_box_add_widget(GNT_BOX(ggc->window), ggc->tv); + } + ggc->info = gnt_vbox_new(FALSE); gnt_box_add_widget(GNT_BOX(ggc->window), ggc->info); @@ -331,13 +530,10 @@ if (type == PURPLE_CONV_TYPE_IM) { g_signal_connect(G_OBJECT(ggc->entry), "text_changed", G_CALLBACK(send_typing_notification), ggc); - purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", finch_conv_get_handle(), - PURPLE_CALLBACK(update_buddy_typing), NULL); - purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", finch_conv_get_handle(), - PURPLE_CALLBACK(update_buddy_typing), NULL); } g_free(title); + gnt_box_give_focus_to_child(GNT_BOX(ggc->window), ggc->entry); } static void @@ -350,6 +546,7 @@ ggc->active_conv = ggc->list->data; if (ggc->list == NULL) { + g_free(ggc->u.chat); gnt_widget_destroy(ggc->window); g_free(ggc); } @@ -380,8 +577,7 @@ gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), "\n", GNT_TEXT_FLAG_NORMAL); /* Unnecessary to print the timestamp for delayed message */ - if (!(flags & PURPLE_MESSAGE_DELAYED) && - purple_prefs_get_bool("/finch/conversations/timestamps")) + if (purple_prefs_get_bool("/finch/conversations/timestamps")) gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), purple_utf8_strftime("(%H:%M:%S) ", localtime(&mtime)), GNT_TEXT_FLAG_DIM); @@ -480,6 +676,20 @@ finch_write_common(conv, name, message, flags, mtime); } +static const char * +chat_flag_text(PurpleConvChatBuddyFlags flags) +{ + if (flags & PURPLE_CBFLAGS_FOUNDER) + return "~"; + if (flags & PURPLE_CBFLAGS_OP) + return "@"; + if (flags & PURPLE_CBFLAGS_HALFOP) + return "%"; + if (flags & PURPLE_CBFLAGS_VOICE) + return "+"; + return " "; +} + static void finch_chat_add_users(PurpleConversation *conv, GList *users, gboolean new_arrivals) { @@ -510,8 +720,11 @@ for (; users; users = users->next) { PurpleConvChatBuddy *cbuddy = users->data; + GntTree *tree = GNT_TREE(ggc->u.chat->userlist); gnt_entry_add_suggest(entry, cbuddy->name); gnt_entry_add_suggest(entry, cbuddy->alias); + gnt_tree_add_row_after(tree, g_strdup(cbuddy->name), + gnt_tree_create_row(tree, chat_flag_text(cbuddy->flags), cbuddy->alias), NULL, NULL); } } @@ -521,42 +734,60 @@ /* Update the name for string completion */ FinchConv *ggc = conv->ui_data; GntEntry *entry = GNT_ENTRY(ggc->entry); + GntTree *tree = GNT_TREE(ggc->u.chat->userlist); + PurpleConvChatBuddy *cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), new_n); + gnt_entry_remove_suggest(entry, old); + gnt_tree_remove(tree, (gpointer)old); + gnt_entry_add_suggest(entry, new_n); gnt_entry_add_suggest(entry, new_a); + gnt_tree_add_row_after(tree, g_strdup(new_n), + gnt_tree_create_row(tree, chat_flag_text(cb->flags), new_a), NULL, NULL); } static void -finch_chat_remove_user(PurpleConversation *conv, GList *list) +finch_chat_remove_users(PurpleConversation *conv, GList *list) { /* Remove the name from string completion */ FinchConv *ggc = conv->ui_data; GntEntry *entry = GNT_ENTRY(ggc->entry); - for (; list; list = list->next) + for (; list; list = list->next) { + GntTree *tree = GNT_TREE(ggc->u.chat->userlist); gnt_entry_remove_suggest(entry, list->data); + gnt_tree_remove(tree, list->data); + } } static void finch_chat_update_user(PurpleConversation *conv, const char *user) { + PurpleConvChatBuddy *cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), user); + FinchConv *ggc = conv->ui_data; + gnt_tree_change_text(GNT_TREE(ggc->u.chat->userlist), (gpointer)user, 0, chat_flag_text(cb->flags)); } static PurpleConversationUiOps conv_ui_ops = { - .create_conversation = finch_create_conversation, - .destroy_conversation = finch_destroy_conversation, - .write_chat = finch_write_chat, - .write_im = finch_write_im, - .write_conv = finch_write_conv, - .chat_add_users = finch_chat_add_users, - .chat_rename_user = finch_chat_rename_user, - .chat_remove_users = finch_chat_remove_user, - .chat_update_user = finch_chat_update_user, - .present = NULL, - .has_focus = NULL, - .custom_smiley_add = NULL, - .custom_smiley_write = NULL, - .custom_smiley_close = NULL + finch_create_conversation, + finch_destroy_conversation, + finch_write_chat, + finch_write_im, + finch_write_conv, + finch_chat_add_users, + finch_chat_rename_user, + finch_chat_remove_users, + finch_chat_update_user, + NULL, /* present */ + NULL, /* has_focus */ + NULL, /* custom_smiley_add */ + NULL, /* custom_smiley_write */ + NULL, /* custom_smiley_close */ + NULL, /* send_confirm */ + NULL, + NULL, + NULL, + NULL }; PurpleConversationUiOps *finch_conv_get_ui_ops() @@ -604,7 +835,7 @@ PurpleCmdStatus status; if (!g_ascii_strcasecmp(args[0], "version")) { - tmp = g_strdup_printf("me is using %s.", VERSION); + tmp = g_strdup_printf("me is using Finch v%s.", VERSION); markup = g_markup_escape_text(tmp, -1); status = purple_cmd_do_command(conv, tmp, markup, error); @@ -677,6 +908,23 @@ return PURPLE_CMD_STATUS_OK; } +static PurpleCmdRet +users_command_cb(PurpleConversation *conv, const char *cmd, char **args, char **error, gpointer data) +{ + FinchConv *fc = conv->ui_data; + FinchConvChat *ch; + if (!fc) + return PURPLE_CMD_STATUS_FAILED; + + ch = fc->u.chat; + gnt_widget_set_visible(ch->userlist, + (GNT_WIDGET_IS_FLAG_SET(ch->userlist, GNT_WIDGET_INVISIBLE))); + gnt_box_readjust(GNT_BOX(fc->window)); + gnt_box_give_focus_to_child(GNT_BOX(fc->window), fc->entry); + purple_prefs_set_bool(PREF_USERLIST, !(GNT_WIDGET_IS_FLAG_SET(ch->userlist, GNT_WIDGET_INVISIBLE))); + return PURPLE_CMD_STATUS_OK; +} + void finch_conversation_init() { purple_prefs_add_none(PREF_ROOT); @@ -686,6 +934,8 @@ purple_prefs_add_none(PREF_ROOT "/position"); purple_prefs_add_int(PREF_ROOT "/position/x", 0); purple_prefs_add_int(PREF_ROOT "/position/y", 0); + purple_prefs_add_none(PREF_CHAT); + purple_prefs_add_bool(PREF_USERLIST, FALSE); /* Xerox the commands */ purple_cmd_register("say", "S", PURPLE_CMD_P_DEFAULT, @@ -703,6 +953,9 @@ purple_cmd_register("help", "w", PURPLE_CMD_P_DEFAULT, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, NULL, help_command_cb, _("help <command>: Help on a specific command."), NULL); + purple_cmd_register("users", "", PURPLE_CMD_P_DEFAULT, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, NULL, + users_command_cb, _("users: Show the list of users in the chat."), NULL); /* Now some commands to bring up some other windows */ purple_cmd_register("plugins", "", PURPLE_CMD_P_DEFAULT, @@ -723,10 +976,18 @@ purple_cmd_register("status", "", PURPLE_CMD_P_DEFAULT, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL, cmd_show_window, _("statuses: Show the savedstatuses window."), finch_savedstatus_show_all); + + purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", finch_conv_get_handle(), + PURPLE_CALLBACK(update_buddy_typing), NULL); + purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", finch_conv_get_handle(), + PURPLE_CALLBACK(update_buddy_typing), NULL); + purple_signal_connect(purple_conversations_get_handle(), "chat-left", finch_conv_get_handle(), + PURPLE_CALLBACK(chat_left_cb), NULL); } void finch_conversation_uninit() { + purple_signals_disconnect_by_handle(finch_conv_get_handle()); } void finch_conversation_set_active(PurpleConversation *conv)