pidgin/pidgin

c51a28d28a2d
Parents 09b500dd62e7
Children e3bd18c1769d
Start implementing the conversation window actions.

Still not sure how we want to handle add/remove and block/unblock, but this is
small set of things to get us started.

Testing Done:
Opened a conversation windown with multiple ims and a chat and verified that items sensitivity was set correctly depending on what was selected and made sure the actions work as well.

Side note, setting aliases on chats appears to have been broken outside of this change.

Reviewed at https://reviews.imfreedom.org/r/1563/
--- 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 @@
}
}
-
-static void
-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 */
- GtkTreeIter iter;
- GtkTreeModel *model;
- GtkTreeSelection *sel;
- char *name;
-
- 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);
- else
- return;
-
- chat_do_info(gtkconv, name);
- g_free(name);
- }
-}
-
static void
block_cb(GtkWidget *widget, PidginConversation *gtkconv)
{
@@ -374,44 +343,6 @@
pidgin_request_add_permit(account, purple_conversation_get_name(conv));
}
-static void
-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, ""))
- return;
-
- message = pidgin_invite_dialog_get_message(dialog);
-
- purple_serv_chat_invite(purple_conversation_get_connection(PURPLE_CONVERSATION(chat)),
- purple_chat_conversation_get_id(chat),
- message, contact);
- }
-
- g_clear_pointer(&invite_dialog, gtk_widget_destroy);
-}
-
-static void
-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);
-}
-
#ifdef USE_VV
static void
menu_initiate_media_call_cb(GtkAction *action, gpointer data)
@@ -432,67 +363,6 @@
#endif
static void
-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);
- }
-
-}
-
-static void
-menu_alias_cb(GtkAction *action, gpointer data)
-{
- PidginConversationWindow *win = data;
- PurpleConversation *conv;
- PurpleAccount *account;
- const char *name;
-
- 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)) {
- PurpleBuddy *b;
-
- b = purple_blist_find_buddy(account, name);
- if (b != NULL)
- pidgin_dialogs_alias_buddy(b);
- } else if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
- PurpleChat *c;
-
- c = purple_blist_find_chat(account, name);
- if (c != NULL)
- pidgin_dialogs_alias_chat(c);
- }
-}
-
-static void
-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));
-}
-
-static void
-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));
-}
-
-static void
menu_block_cb(GtkAction *action, gpointer data)
{
PidginConversationWindow *win = data;
@@ -526,14 +396,6 @@
}
static void
-menu_close_conv_cb(GtkAction *action, gpointer data)
-{
- PidginConversationWindow *win = data;
-
- close_conv_cb(NULL, PIDGIN_CONVERSATION(pidgin_conversation_window_get_selected(win)));
-}
-
-static void
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) },
#endif
- { "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);
g_free(gtkconv);
@@ -1975,6 +1834,7 @@
if (gtkconv->attach_timer) {
g_source_remove(gtkconv->attach_timer);
+ gtkconv->attach_timer = 0;
}
g_free(gtkconv);
--- 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 "gtkconv.h"
+#include "gtkdialogs.h"
+#include "gtkutils.h"
+#include "pidgininvitedialog.h"
enum {
PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT,
@@ -61,6 +64,226 @@
static GtkWidget *default_window = NULL;
/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+pidgin_conversation_window_actions_set_enabled(PurpleConversation *conversation,
+ GActionMap *map,
+ const gchar **actions,
+ gboolean enabled)
+{
+ gint i = 0;
+
+ for(i = 0; actions[i] != NULL; i++) {
+ GAction *action = NULL;
+ const gchar *name = actions[i];
+
+ action = g_action_map_lookup_action(map, name);
+ if(action != NULL) {
+ g_simple_action_set_enabled(G_SIMPLE_ACTION(action), enabled);
+ } else {
+ g_critical("Failed to find action named %s", name);
+ }
+ }
+}
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+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),
+ message, contact);
+ }
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(invite_dialog));
+}
+
+/******************************************************************************
+ * Actions
+ *****************************************************************************/
+static void
+pidgin_conversation_window_alias(G_GNUC_UNUSED GSimpleAction *simple,
+ G_GNUC_UNUSED GVariant *parameter,
+ gpointer data)
+{
+ PidginConversationWindow *window = data;
+ PurpleConversation *selected = NULL;
+
+ selected = pidgin_conversation_window_get_selected(window);
+ if(PURPLE_IS_CONVERSATION(selected)) {
+ PurpleAccount *account;
+ const gchar *name;
+
+ 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);
+ }
+ }
+ }
+}
+
+static void
+pidgin_conversation_window_close_conversation(G_GNUC_UNUSED GSimpleAction *simple,
+ G_GNUC_UNUSED GVariant *parameter,
+ gpointer data)
+{
+ 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);
+ }
+}
+
+static void
+pidgin_conversation_window_get_info(G_GNUC_UNUSED GSimpleAction *simple,
+ G_GNUC_UNUSED GVariant *parameter,
+ gpointer data)
+{
+ 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));
+ }
+ }
+}
+
+static void
+pidgin_conversation_window_invite(G_GNUC_UNUSED GSimpleAction *simple,
+ G_GNUC_UNUSED GVariant *parameter,
+ gpointer data)
+{
+ 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",
+ invite_dialog);
+
+ gtk_window_set_transient_for(GTK_WINDOW(invite_dialog),
+ GTK_WINDOW(window));
+ gtk_window_set_destroy_with_parent(GTK_WINDOW(invite_dialog), TRUE);
+
+ g_signal_connect(invite_dialog, "response",
+ G_CALLBACK(pidgin_conversation_window_invite_cb),
+ NULL);
+ }
+
+ gtk_widget_show_all(invite_dialog);
+ }
+}
+
+static void
+pidgin_conversation_window_send_file(G_GNUC_UNUSED GSimpleAction *simple,
+ G_GNUC_UNUSED GVariant *parameter,
+ gpointer data)
+{
+ 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),
+ NULL);
+ }
+}
+
+static GActionEntry win_entries[] = {
+ {
+ .name = "alias",
+ .activate = pidgin_conversation_window_alias
+ }, {
+ .name = "close",
+ .activate = pidgin_conversation_window_close_conversation
+ }, {
+ .name = "get-info",
+ .activate = pidgin_conversation_window_get_info
+ }, {
+ .name = "invite",
+ .activate = pidgin_conversation_window_invite
+ }, {
+ .name = "send-file",
+ .activate = pidgin_conversation_window_send_file
+ }
+};
+
+/*<private>
+ * 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[] = {
+ "alias",
+ "close",
+ "get-info",
+ NULL
+};
+
+static const gchar *pidgin_conversation_window_im_conversation_actions[] = {
+ "send-file",
+ NULL
+};
+
+static const gchar *pidgin_conversation_window_chat_conversation_actions[] = {
+ "invite",
+ NULL
+};
+
+/******************************************************************************
* Callbacks
*****************************************************************************/
static void
@@ -73,16 +296,49 @@
gboolean changed = FALSE;
if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
+ GObject *obj;
+ gboolean is_conversation = FALSE;
+ gboolean im_selected = FALSE, chat_selected = FALSE;
gchar *name = NULL;
gtk_tree_model_get(model, &iter,
PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, &name,
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &obj,
-1);
gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name);
g_free(name);
changed = TRUE;
+
+ /* If a conversation is selected, enable the generic conversation
+ * actions.
+ */
+ is_conversation = PURPLE_IS_CONVERSATION(obj);
+ pidgin_conversation_window_actions_set_enabled(PURPLE_CONVERSATION(obj),
+ G_ACTION_MAP(window),
+ pidgin_conversation_window_conversation_actions,
+ is_conversation);
+
+ /* If an IM is selected, enable the IM-specific actions otherwise
+ * disable them.
+ */
+ im_selected = PURPLE_IS_IM_CONVERSATION(obj);
+ pidgin_conversation_window_actions_set_enabled(PURPLE_CONVERSATION(obj),
+ G_ACTION_MAP(window),
+ pidgin_conversation_window_im_conversation_actions,
+ im_selected);
+
+ /* If a chat is selected, enable the chat-specific actions otherwise
+ * disable them.
+ */
+ chat_selected = PURPLE_IS_CHAT_CONVERSATION(obj);
+ pidgin_conversation_window_actions_set_enabled(PURPLE_CONVERSATION(obj),
+ G_ACTION_MAP(window),
+ pidgin_conversation_window_chat_conversation_actions,
+ chat_selected);
+
+ g_clear_object(&obj);
}
if(!changed) {
@@ -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 @@
-1);
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),
+ name);
+ if(GTK_IS_WIDGET(child)) {
+ gtk_container_remove(GTK_CONTAINER(window->stack), child);
+ }
+
gtk_tree_store_remove(window->model, &iter);
g_clear_object(&obj);
--- 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 @@
<item>
<attribute name="label" translatable="yes">New Instant _Message...</attribute>
<attribute name="action">app.new-message</attribute>
- <attribute name="accel">&lt;Primary&gt;M</attribute>
+ <attribute name="accel">&lt;Primary&gt;m</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Join a _Chat...</attribute>
@@ -84,19 +84,6 @@
</section>
<section>
- <item>
- <attribute name="label" translatable="yes">_Find...</attribute>
- <attribute name="action">win.find</attribute>
- <attribute name="accel">&lt;Primary&gt;F</attribute>
- </item>
- <item>
- <attribute name="label" translatable="yes">Clea_r Scrollback</attribute>
- <attribute name="action">win.clear-history</attribute>
- <attribute name="accel">&lt;Primary&gt;L</attribute>
- </item>
- </section>
-
- <section>
<submenu>
<attribute name="label" translatable="yes">M_edia</attribute>
@@ -124,8 +111,8 @@
</item>
<item>
<attribute name="label" translatable="yes">_Get Info</attribute>
- <attribute name="action">win.clear-history</attribute>
- <attribute name="accel">&lt;Primary&gt;O</attribute>
+ <attribute name="action">win.get-info</attribute>
+ <attribute name="accel">&lt;Primary&gt;o</attribute>
</item>
<item>
<attribute name="label" translatable="yes">In_vite...</attribute>
@@ -155,20 +142,9 @@
<section>
<item>
- <attribute name="label" translatable="yes">Insert Lin_k...</attribute>
- <attribute name="action">win.insert-link</attribute>
- </item>
- <item>
- <attribute name="label" translatable="yes">Insert Imag_e...</attribute>
- <attribute name="action">win.insert-image</attribute>
- </item>
- </section>
-
- <section>
- <item>
<attribute name="label" translatable="yes">_Close</attribute>
<attribute name="action">win.close</attribute>
- <attribute name="accel">&lt;Primary&gt;W</attribute>
+ <attribute name="accel">&lt;Primary&gt;w</attribute>
</item>
</section>
</submenu>