--- a/pidgin/gtkconv.c Mon Aug 08 20:23:17 2022 -0500
+++ b/pidgin/gtkconv.c Mon Aug 08 22:03:04 2022 -0500
@@ -71,8 +71,6 @@
#define BUDDYICON_SIZE_MIN 32
#define BUDDYICON_SIZE_MAX 96
-static GtkWidget *invite_dialog = NULL;
/* Prototypes. <-- because Paco-Paco hates this comment. */
static void got_typing_keypress(PidginConversation *gtkconv, gboolean first);
static void add_chat_user_common(PurpleChatConversation *chat, PurpleChatUser *cb, const char *old_name);
@@ -321,35 +319,6 @@
-info_cb(GtkWidget *widget, PidginConversation *gtkconv)
- PurpleConversation *conv = gtkconv->active_conv;
- if (PURPLE_IS_IM_CONVERSATION(conv)) {
- pidgin_retrieve_user_info(purple_conversation_get_connection(conv),
- purple_conversation_get_name(conv));
- } else if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
- /* Get info of the person currently selected in the GtkTreeView */
- model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkconv->list));
- sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkconv->list));
- if (gtk_tree_selection_get_selected(sel, NULL, &iter))
- gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &name, -1);
- chat_do_info(gtkconv, name);
block_cb(GtkWidget *widget, PidginConversation *gtkconv)
@@ -374,44 +343,6 @@
pidgin_request_add_permit(account, purple_conversation_get_name(conv));
-do_invite(GtkWidget *w, int resp, gpointer data)
- PidginInviteDialog *dialog = PIDGIN_INVITE_DIALOG(w);
- PurpleChatConversation *chat = pidgin_invite_dialog_get_conversation(dialog);
- const gchar *contact, *message;
- if (resp == GTK_RESPONSE_ACCEPT) {
- contact = pidgin_invite_dialog_get_contact(dialog);
- if (!g_ascii_strcasecmp(contact, ""))
- message = pidgin_invite_dialog_get_message(dialog);
- purple_serv_chat_invite(purple_conversation_get_connection(PURPLE_CONVERSATION(chat)),
- purple_chat_conversation_get_id(chat),
- g_clear_pointer(&invite_dialog, gtk_widget_destroy);
-invite_cb(GtkWidget *widget, PidginConversation *gtkconv)
- PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(gtkconv->active_conv);
- if (invite_dialog == NULL) {
- invite_dialog = pidgin_invite_dialog_new(chat);
- /* Connect the signals. */
- g_signal_connect(G_OBJECT(invite_dialog), "response",
- G_CALLBACK(do_invite), NULL);
- gtk_widget_show_all(invite_dialog);
menu_initiate_media_call_cb(GtkAction *action, gpointer data)
@@ -432,67 +363,6 @@
-menu_send_file_cb(GtkAction *action, gpointer data)
- PidginConversationWindow *win = data;
- PurpleConversation *conv = pidgin_conversation_window_get_selected(win);
- if (PURPLE_IS_IM_CONVERSATION(conv)) {
- purple_serv_send_file(purple_conversation_get_connection(conv), purple_conversation_get_name(conv), NULL);
-menu_alias_cb(GtkAction *action, gpointer data)
- PidginConversationWindow *win = data;
- PurpleConversation *conv;
- PurpleAccount *account;
- conv = pidgin_conversation_window_get_selected(win);
- account = purple_conversation_get_account(conv);
- name = purple_conversation_get_name(conv);
- if (PURPLE_IS_IM_CONVERSATION(conv)) {
- b = purple_blist_find_buddy(account, name);
- pidgin_dialogs_alias_buddy(b);
- } else if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
- c = purple_blist_find_chat(account, name);
- pidgin_dialogs_alias_chat(c);
-menu_get_info_cb(GtkAction *action, gpointer data)
- PidginConversationWindow *win = data;
- PurpleConversation *conv;
- conv = pidgin_conversation_window_get_selected(win);
- info_cb(NULL, PIDGIN_CONVERSATION(conv));
-menu_invite_cb(GtkAction *action, gpointer data)
- PidginConversationWindow *win = data;
- PurpleConversation *conv;
- conv = pidgin_conversation_window_get_selected(win);
- invite_cb(NULL, PIDGIN_CONVERSATION(conv));
menu_block_cb(GtkAction *action, gpointer data)
PidginConversationWindow *win = data;
@@ -526,14 +396,6 @@
-menu_close_conv_cb(GtkAction *action, gpointer data)
- PidginConversationWindow *win = data;
- close_conv_cb(NULL, PIDGIN_CONVERSATION(pidgin_conversation_window_get_selected(win)));
chat_do_im(PidginConversation *gtkconv, const char *who)
PurpleConversation *conv = gtkconv->active_conv;
@@ -1142,18 +1004,10 @@
{ "AudioVideoCall", NULL, N_("Audio/Video _Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) },
- { "SendFile", NULL, N_("Se_nd File..."), NULL, NULL, G_CALLBACK(menu_send_file_cb) },
- { "GetInfo", NULL, N_("_Get Info"), "<control>O", NULL, G_CALLBACK(menu_get_info_cb) },
- { "Invite", NULL, N_("In_vite..."), NULL, NULL, G_CALLBACK(menu_invite_cb) },
- { "MoreMenu", NULL, N_("M_ore"), NULL, NULL, NULL },
- { "Alias", NULL, N_("Al_ias..."), NULL, NULL, G_CALLBACK(menu_alias_cb) },
{ "Block", NULL, N_("_Block..."), NULL, NULL, G_CALLBACK(menu_block_cb) },
{ "Unblock", NULL, N_("_Unblock..."), NULL, NULL, G_CALLBACK(menu_unblock_cb) },
{ "Add", NULL, N_("_Add..."), NULL, NULL, G_CALLBACK(menu_add_remove_cb) },
{ "Remove", NULL, N_("_Remove..."), NULL, NULL, G_CALLBACK(menu_add_remove_cb) },
- { "InsertLink", NULL, N_("Insert Lin_k..."), NULL, NULL, NULL },
- { "InsertImage", NULL, N_("Insert Imag_e..."), NULL, NULL, NULL },
- { "Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(menu_close_conv_cb) },
/**************************************************************************
@@ -1913,6 +1767,11 @@
if(PIDGIN_IS_PIDGIN_CONVERSATION(conv)) {
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
+ if(gtkconv->attach_timer > 0) { + g_source_remove(gtkconv->attach_timer); + gtkconv->attach_timer = 0; close_conv_cb(NULL, gtkconv);
@@ -1975,6 +1834,7 @@
if (gtkconv->attach_timer) {
g_source_remove(gtkconv->attach_timer);
+ gtkconv->attach_timer = 0; --- a/pidgin/pidginconversationwindow.c Mon Aug 08 20:23:17 2022 -0500
+++ b/pidgin/pidginconversationwindow.c Mon Aug 08 22:03:04 2022 -0500
@@ -25,6 +25,9 @@
#include "pidginconversationwindow.h"
+#include "pidgininvitedialog.h" PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT,
@@ -61,6 +64,226 @@
static GtkWidget *default_window = NULL;
/******************************************************************************
+ *****************************************************************************/ +pidgin_conversation_window_actions_set_enabled(PurpleConversation *conversation, + for(i = 0; actions[i] != NULL; i++) { + GAction *action = NULL; + const gchar *name = actions[i]; + action = g_action_map_lookup_action(map, name); + g_simple_action_set_enabled(G_SIMPLE_ACTION(action), enabled); + g_critical("Failed to find action named %s", name); +/****************************************************************************** + *****************************************************************************/ +pidgin_conversation_window_invite_cb(GtkDialog *dialog, gint response_id, + G_GNUC_UNUSED gpointer data) + PidginInviteDialog *invite_dialog = PIDGIN_INVITE_DIALOG(dialog); + PurpleChatConversation *chat = NULL; + chat = pidgin_invite_dialog_get_conversation(invite_dialog); + g_object_set_data(G_OBJECT(chat), "pidgin-invite-dialog", NULL); + if(response_id == GTK_RESPONSE_ACCEPT) { + const gchar *contact = NULL, *message = NULL; + contact = pidgin_invite_dialog_get_contact(invite_dialog); + message = pidgin_invite_dialog_get_message(invite_dialog); + if(!purple_strequal(contact, "")) { + PurpleConnection *connection = NULL; + connection = purple_conversation_get_connection(PURPLE_CONVERSATION(chat)); + purple_serv_chat_invite(connection, + purple_chat_conversation_get_id(chat), + gtk_widget_destroy(GTK_WIDGET(invite_dialog)); +/****************************************************************************** + *****************************************************************************/ +pidgin_conversation_window_alias(G_GNUC_UNUSED GSimpleAction *simple, + G_GNUC_UNUSED GVariant *parameter, + PidginConversationWindow *window = data; + PurpleConversation *selected = NULL; + selected = pidgin_conversation_window_get_selected(window); + if(PURPLE_IS_CONVERSATION(selected)) { + PurpleAccount *account; + account = purple_conversation_get_account(selected); + name = purple_conversation_get_name(selected); + if(PURPLE_IS_IM_CONVERSATION(selected)) { + PurpleBuddy *buddy = purple_blist_find_buddy(account, name); + if(PURPLE_IS_BUDDY(buddy)) { + pidgin_dialogs_alias_buddy(buddy); + } else if(PURPLE_IS_CHAT_CONVERSATION(selected)) { + PurpleChat *chat = purple_blist_find_chat(account, name); + if(PURPLE_IS_CHAT(chat)) { + pidgin_dialogs_alias_chat(chat); +pidgin_conversation_window_close_conversation(G_GNUC_UNUSED GSimpleAction *simple, + G_GNUC_UNUSED GVariant *parameter, + PidginConversationWindow *window = data; + PurpleConversation *selected = NULL; + selected = pidgin_conversation_window_get_selected(window); + if(PURPLE_IS_CONVERSATION(selected)) { + pidgin_conversation_window_remove(window, selected); + pidgin_conversation_detach(selected); +pidgin_conversation_window_get_info(G_GNUC_UNUSED GSimpleAction *simple, + G_GNUC_UNUSED GVariant *parameter, + PidginConversationWindow *window = data; + PurpleConversation *selected = NULL; + selected = pidgin_conversation_window_get_selected(window); + if(PURPLE_IS_CONVERSATION(selected)) { + if(PURPLE_IS_IM_CONVERSATION(selected)) { + PurpleConnection *connection = NULL; + connection = purple_conversation_get_connection(selected); + pidgin_retrieve_user_info(connection, + purple_conversation_get_name(selected)); +pidgin_conversation_window_invite(G_GNUC_UNUSED GSimpleAction *simple, + G_GNUC_UNUSED GVariant *parameter, + PidginConversationWindow *window = data; + PurpleConversation *selected = NULL; + selected = pidgin_conversation_window_get_selected(window); + if(PURPLE_IS_CHAT_CONVERSATION(selected)) { + GtkWidget *invite_dialog = NULL; + invite_dialog = g_object_get_data(G_OBJECT(selected), + "pidgin-invite-dialog"); + if(!GTK_IS_WIDGET(invite_dialog)) { + invite_dialog = pidgin_invite_dialog_new(PURPLE_CHAT_CONVERSATION(selected)); + g_object_set_data(G_OBJECT(selected), "pidgin-invite-dialog", + gtk_window_set_transient_for(GTK_WINDOW(invite_dialog), + gtk_window_set_destroy_with_parent(GTK_WINDOW(invite_dialog), TRUE); + g_signal_connect(invite_dialog, "response", + G_CALLBACK(pidgin_conversation_window_invite_cb), + gtk_widget_show_all(invite_dialog); +pidgin_conversation_window_send_file(G_GNUC_UNUSED GSimpleAction *simple, + G_GNUC_UNUSED GVariant *parameter, + PidginConversationWindow *window = data; + PurpleConversation *selected = NULL; + selected = pidgin_conversation_window_get_selected(window); + if(PURPLE_IS_IM_CONVERSATION(selected)) { + PurpleConnection *connection = NULL; + connection = purple_conversation_get_connection(selected); + purple_serv_send_file(connection, + purple_conversation_get_name(selected), +static GActionEntry win_entries[] = { + .activate = pidgin_conversation_window_alias + .activate = pidgin_conversation_window_close_conversation + .activate = pidgin_conversation_window_get_info + .activate = pidgin_conversation_window_invite + .activate = pidgin_conversation_window_send_file + * pidgin_conversation_window_conversation_actions: + * A list of action names that are only valid if a conversation is selected. +static const gchar *pidgin_conversation_window_conversation_actions[] = { +static const gchar *pidgin_conversation_window_im_conversation_actions[] = { +static const gchar *pidgin_conversation_window_chat_conversation_actions[] = { +/****************************************************************************** *****************************************************************************/
@@ -73,16 +296,49 @@
gboolean changed = FALSE;
if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
+ gboolean is_conversation = FALSE; + gboolean im_selected = FALSE, chat_selected = FALSE; gtk_tree_model_get(model, &iter,
PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, &name,
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &obj, gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name);
+ /* If a conversation is selected, enable the generic conversation + is_conversation = PURPLE_IS_CONVERSATION(obj); + pidgin_conversation_window_actions_set_enabled(PURPLE_CONVERSATION(obj), + pidgin_conversation_window_conversation_actions, + /* If an IM is selected, enable the IM-specific actions otherwise + im_selected = PURPLE_IS_IM_CONVERSATION(obj); + pidgin_conversation_window_actions_set_enabled(PURPLE_CONVERSATION(obj), + pidgin_conversation_window_im_conversation_actions, + /* If a chat is selected, enable the chat-specific actions otherwise + chat_selected = PURPLE_IS_CHAT_CONVERSATION(obj); + pidgin_conversation_window_actions_set_enabled(PURPLE_CONVERSATION(obj), + pidgin_conversation_window_chat_conversation_actions, @@ -180,6 +436,9 @@
gtk_window_set_application(GTK_WINDOW(window),
GTK_APPLICATION(g_application_get_default()));
+ g_action_map_add_action_entries(G_ACTION_MAP(window), win_entries, + G_N_ELEMENTS(win_entries), window); key = gtk_event_controller_key_new(GTK_WIDGET(window));
gtk_event_controller_set_propagation_phase(key, GTK_PHASE_CAPTURE);
g_signal_connect(G_OBJECT(key), "key-pressed",
@@ -368,6 +627,16 @@
if(PURPLE_CONVERSATION(obj) == conversation) {
+ GtkWidget *child = NULL; + const gchar *name = NULL; + name = purple_conversation_get_name(conversation); + child = gtk_stack_get_child_by_name(GTK_STACK(window->stack), + if(GTK_IS_WIDGET(child)) { + gtk_container_remove(GTK_CONTAINER(window->stack), child); gtk_tree_store_remove(window->model, &iter);
--- a/pidgin/resources/gtk/menus.ui Mon Aug 08 20:23:17 2022 -0500
+++ b/pidgin/resources/gtk/menus.ui Mon Aug 08 22:03:04 2022 -0500
@@ -75,7 +75,7 @@
<attribute name="label" translatable="yes">New Instant _Message...</attribute>
<attribute name="action">app.new-message</attribute>
- <attribute name="accel"><Primary>M</attribute>
+ <attribute name="accel"><Primary>m</attribute> <attribute name="label" translatable="yes">Join a _Chat...</attribute>
@@ -84,19 +84,6 @@
- <attribute name="label" translatable="yes">_Find...</attribute>
- <attribute name="action">win.find</attribute>
- <attribute name="accel"><Primary>F</attribute>
- <attribute name="label" translatable="yes">Clea_r Scrollback</attribute>
- <attribute name="action">win.clear-history</attribute>
- <attribute name="accel"><Primary>L</attribute>
<attribute name="label" translatable="yes">M_edia</attribute>
@@ -124,8 +111,8 @@
<attribute name="label" translatable="yes">_Get Info</attribute>
- <attribute name="action">win.clear-history</attribute>
- <attribute name="accel"><Primary>O</attribute>
+ <attribute name="action">win.get-info</attribute> + <attribute name="accel"><Primary>o</attribute> <attribute name="label" translatable="yes">In_vite...</attribute>
@@ -155,20 +142,9 @@
- <attribute name="label" translatable="yes">Insert Lin_k...</attribute>
- <attribute name="action">win.insert-link</attribute>
- <attribute name="label" translatable="yes">Insert Imag_e...</attribute>
- <attribute name="action">win.insert-image</attribute>
<attribute name="label" translatable="yes">_Close</attribute>
<attribute name="action">win.close</attribute>
- <attribute name="accel"><Primary>W</attribute>
+ <attribute name="accel"><Primary>w</attribute>