pidgin/pidgin

Modernize the AccountEditor.

20 months ago, Gary Kramlich
6ccdb4116ca2
Parents ba1699ed5d56
Children e1d3677c844b
Modernize the AccountEditor.

This now uses libadwaita for everything, but will need some updates when
libadwaita 1.2 is released. Avatars are currently non-functional as the existing
buddy icon API leaves a lot to be desired and doesn't work for what we're trying
to do here.

Testing Done:
* Created new accounts with the new dialog.
* Modified accounts with the new dialog.
* Modified accounts with the old dialog and verified the changes showed up in the old dialog.
* Created accounts with the old dialog and verified they were displayed properly by the new dialog.

Bugs closed: PIDGIN-17592

Reviewed at https://reviews.imfreedom.org/r/1737/
--- a/pidgin/pidginaccounteditor.c Thu Sep 15 20:59:06 2022 -0500
+++ b/pidgin/pidginaccounteditor.c Thu Sep 15 22:32:05 2022 -0500
@@ -22,17 +22,48 @@
#include <glib/gi18n-lib.h>
+#include <adwaita.h>
+
#include "pidginaccounteditor.h"
-#include "pidginproxyoptions.h"
+#include "pidginprotocolchooser.h"
struct _PidginAccountEditor {
GtkDialog parent;
PurpleAccount *account;
- GtkWidget *notebook;
+ /* Login Options */
+ GtkWidget *login_options;
+ GtkWidget *protocol;
+ GtkWidget *username;
+
+ GList *user_split_entries;
+ GList *user_split_rows;
+
+ /* User Options */
+ GtkWidget *alias;
+
+ GtkFileChooserNative *avatar_dialog;
+ GdkPixbuf *avatar_pixbuf;
+ GtkWidget *avatar_row;
+ GtkWidget *use_custom_avatar;
+ GtkWidget *avatar;
+
+ /* Advanced Options */
+ GtkWidget *advanced_group;
+ GtkWidget *advanced_toggle;
+
+ GList *advanced_entries;
+ GList *advanced_rows;
+
+ /* Proxy Options */
+ GtkWidget *proxy_type;
GtkWidget *proxy_options;
+ GtkWidget *proxy_host;
+ GtkWidget *proxy_port;
+ GtkWidget *proxy_username;
+ GtkWidget *proxy_password;
};
enum {
@@ -42,49 +73,833 @@
};
static GParamSpec *properties[N_PROPERTIES] = {NULL, };
+
+/******************************************************************************
+ * Prototypes
+ *****************************************************************************/
+static void pidgin_account_editor_connection_changed_cb(GObject *obj,
+ GParamSpec *pspec,
+ gpointer data);
+
/******************************************************************************
* Helpers
*****************************************************************************/
static void
+pidgin_account_editor_add_user_split(gpointer data, gpointer user_data) {
+ PurpleAccountUserSplit *split = data;
+ PidginAccountEditor *editor = user_data;
+ GtkWidget *entry = NULL;
+
+ if(!purple_account_user_split_is_constant(split)) {
+ GtkWidget *row = NULL;
+
+ row = adw_action_row_new();
+ editor->user_split_rows = g_list_append(editor->user_split_rows, row);
+ adw_preferences_group_add(ADW_PREFERENCES_GROUP(editor->login_options),
+ row);
+
+ adw_preferences_row_set_title(ADW_PREFERENCES_ROW(row),
+ purple_account_user_split_get_text(split));
+
+ entry = gtk_entry_new();
+ gtk_widget_set_hexpand(entry, TRUE);
+ gtk_widget_set_valign(entry, GTK_ALIGN_CENTER);
+ adw_action_row_add_suffix(ADW_ACTION_ROW(row), entry);
+ adw_action_row_set_activatable_widget(ADW_ACTION_ROW(row), entry);
+ }
+
+ editor->user_split_entries = g_list_append(editor->user_split_entries,
+ entry);
+}
+
+static gboolean
+pidgin_account_editor_update_login_options(PidginAccountEditor *editor,
+ PurpleProtocol *protocol)
+{
+ GList *user_splits = NULL;
+ GList *split_item = NULL;
+ GList *entry_item = NULL;
+ gchar *username = NULL;
+
+ /* Clear out the old user splits from our list. */
+ g_clear_pointer(&editor->user_split_entries, g_list_free);
+
+ /* Now remove the rows we added to the preference group for each non
+ * constant user split.
+ */
+ while(editor->user_split_rows != NULL) {
+ adw_preferences_group_remove(ADW_PREFERENCES_GROUP(editor->login_options),
+ editor->user_split_rows->data);
+
+ editor->user_split_rows = g_list_delete_link(editor->user_split_rows,
+ editor->user_split_rows);
+ }
+
+ /* Add the user splits for the protocol. */
+ user_splits = purple_protocol_get_user_splits(protocol);
+ g_list_foreach(user_splits, pidgin_account_editor_add_user_split, editor);
+
+ /* If we have an account, populate its values. */
+ if(PURPLE_IS_ACCOUNT(editor->account)) {
+ /* The username will be split apart below and eventually set as the text
+ * in the username entry.
+ */
+ username = g_strdup(purple_account_get_username(editor->account));
+ }
+
+ /* Filling out the user splits is a pain. If we have an account, we created
+ * a copy of the username above. We then iterate the user splits backwards
+ * so we can insert a null terminator at the start of each split we find in
+ * the username.
+ */
+ split_item = g_list_last(user_splits);
+ entry_item = g_list_last(editor->user_split_entries);
+ while(split_item != NULL && entry_item != NULL) {
+ GtkWidget *entry = entry_item->data;
+ PurpleAccountUserSplit *split = split_item->data;
+ gchar *ptr = NULL;
+ const gchar *value = NULL;
+
+ if(username != NULL) {
+ gchar sep = purple_account_user_split_get_separator(split);
+
+ if(purple_account_user_split_get_reverse(split)) {
+ ptr = strrchr(username, sep);
+ } else {
+ ptr = strchr(username, sep);
+ }
+
+ if(ptr != NULL) {
+ /* Insert a null terminator in place of the separator. */
+ *ptr = '\0';
+
+ /* Set the value to the first byte after the separator. */
+ value = ptr + 1;
+ }
+ }
+
+ if(value == NULL) {
+ value = purple_account_user_split_get_default_value(split);
+ }
+
+ if(value != NULL && GTK_IS_ENTRY(entry)) {
+ gtk_editable_set_text(GTK_EDITABLE(entry), value);
+ }
+
+ split_item = split_item->prev;
+ entry_item = entry_item->prev;
+ }
+
+ /* Free the user splits. */
+ g_list_free_full(user_splits,
+ (GDestroyNotify)purple_account_user_split_destroy);
+
+ /* Set the username entry to the remaining text in username and free our
+ * copy of said username.
+ */
+ if(username != NULL) {
+ gtk_editable_set_text(GTK_EDITABLE(editor->username), username);
+ g_free(username);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+pidgin_account_editor_update_user_options(PidginAccountEditor *editor,
+ PurpleProtocol *protocol)
+{
+ PurpleBuddyIconSpec *icon_spec = NULL;
+ PurpleImage *image = NULL;
+ gboolean show_avatar_opts = TRUE;
+ const gchar *svalue = "";
+ gboolean use_global = TRUE;
+
+ /* Check if the protocol supports avatars. */
+ icon_spec = purple_protocol_get_icon_spec(protocol);
+ show_avatar_opts = (icon_spec != NULL && icon_spec->format != NULL);
+ purple_buddy_icon_spec_free(icon_spec);
+
+ gtk_widget_set_visible(editor->avatar_row, show_avatar_opts);
+
+ /* Determine our values. */
+ if(editor->account != NULL) {
+ svalue = purple_account_get_private_alias(editor->account);
+ image = purple_buddy_icons_find_account_icon(editor->account);
+ use_global = purple_account_get_bool(editor->account,
+ "use-global-buddyicon", TRUE);
+ }
+
+ if(svalue == NULL) {
+ svalue = "";
+ }
+
+ gtk_editable_set_text(GTK_EDITABLE(editor->alias), svalue);
+ gtk_switch_set_active(GTK_SWITCH(editor->use_custom_avatar), !use_global);
+
+ g_clear_object(&editor->avatar_pixbuf);
+ if(PURPLE_IS_IMAGE(image)) {
+ editor->avatar_pixbuf = purple_gdk_pixbuf_from_image(image);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(editor->avatar),
+ editor->avatar_pixbuf);
+ } else {
+ gtk_image_set_from_icon_name(GTK_IMAGE(editor->avatar),
+ "select-avatar");
+ }
+}
+
+static gboolean
+pidgin_account_editor_advanced_option_use_default(PidginAccountEditor *editor) {
+ PurpleProtocol *protocol = NULL;
+
+ /* If this is the new dialog, use the default value. */
+ if(!PURPLE_IS_ACCOUNT(editor->account)) {
+ return TRUE;
+ }
+
+ /* If we have an existing account, check if the protocol has changed. */
+ protocol = pidgin_protocol_chooser_get_protocol(PIDGIN_PROTOCOL_CHOOSER(editor->protocol));
+ if(protocol != purple_account_get_protocol(editor->account)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GtkWidget *
+pidgin_account_editor_add_advanced_boolean(PidginAccountEditor *editor,
+ PurpleAccountOption *option)
+{
+ GtkWidget *row = NULL;
+ GtkWidget *toggle = NULL;
+ gboolean value = FALSE;
+ gchar *title = NULL;
+
+ if(pidgin_account_editor_advanced_option_use_default(editor)) {
+ value = purple_account_option_get_default_bool(option);
+ } else {
+ const gchar *setting = purple_account_option_get_setting(option);
+ gboolean def_value = purple_account_option_get_default_bool(option);
+
+ value = purple_account_get_bool(editor->account, setting, def_value);
+ }
+
+ /* Create the row and set its title with a mnemonic. */
+ row = adw_action_row_new();
+ g_object_bind_property(editor->advanced_toggle, "active", row, "visible",
+ G_BINDING_SYNC_CREATE);
+ adw_preferences_row_set_use_underline(ADW_PREFERENCES_ROW(row), TRUE);
+ title = g_strdup_printf("_%s", purple_account_option_get_text(option));
+ adw_preferences_row_set_title(ADW_PREFERENCES_ROW(row), title);
+ g_free(title);
+
+ adw_preferences_group_add(ADW_PREFERENCES_GROUP(editor->advanced_group),
+ row);
+
+ /* Add the row to the editor's list of advanced rows. */
+ editor->advanced_rows = g_list_append(editor->advanced_rows, row);
+
+ /* Create the input widget. */
+ toggle = gtk_switch_new();
+ gtk_switch_set_active(GTK_SWITCH(toggle), value);
+ gtk_widget_set_valign(toggle, GTK_ALIGN_CENTER);
+ adw_action_row_add_suffix(ADW_ACTION_ROW(row), toggle);
+ adw_action_row_set_activatable_widget(ADW_ACTION_ROW(row), toggle);
+
+ return toggle;
+}
+
+static GtkWidget *
+pidgin_account_editor_add_advanced_int(PidginAccountEditor *editor,
+ PurpleAccountOption *option)
+{
+ GtkWidget *row = NULL;
+ GtkWidget *entry = NULL;
+ gint value = 0;
+ gchar *title = NULL;
+ gchar *svalue = NULL;
+
+ if(pidgin_account_editor_advanced_option_use_default(editor)) {
+ value = purple_account_option_get_default_int(option);
+ } else {
+ const gchar *setting = purple_account_option_get_setting(option);
+ gint def_value = purple_account_option_get_default_int(option);
+
+ value = purple_account_get_int(editor->account, setting, def_value);
+ }
+
+ /* Create the row and set its title with a mnemonic. */
+ row = adw_action_row_new();
+ g_object_bind_property(editor->advanced_toggle, "active", row, "visible",
+ G_BINDING_SYNC_CREATE);
+ adw_preferences_row_set_use_underline(ADW_PREFERENCES_ROW(row), TRUE);
+ title = g_strdup_printf("_%s", purple_account_option_get_text(option));
+ adw_preferences_row_set_title(ADW_PREFERENCES_ROW(row), title);
+ g_free(title);
+
+ adw_preferences_group_add(ADW_PREFERENCES_GROUP(editor->advanced_group),
+ row);
+
+ /* Add the row to the editor's list of advanced rows. */
+ editor->advanced_rows = g_list_append(editor->advanced_rows, row);
+
+ /* Create the input widget. */
+ entry = gtk_entry_new();
+ gtk_entry_set_input_purpose(GTK_ENTRY(entry), GTK_INPUT_PURPOSE_DIGITS);
+ svalue = g_strdup_printf("%d", value);
+ gtk_editable_set_text(GTK_EDITABLE(entry), svalue);
+ g_free(svalue);
+
+ gtk_widget_set_hexpand(entry, TRUE);
+ gtk_widget_set_valign(entry, GTK_ALIGN_CENTER);
+ adw_action_row_add_suffix(ADW_ACTION_ROW(row), entry);
+ adw_action_row_set_activatable_widget(ADW_ACTION_ROW(row), entry);
+
+ return entry;
+}
+
+static GtkWidget *
+pidgin_account_editor_add_advanced_string(PidginAccountEditor *editor,
+ PurpleAccountOption *option)
+{
+ GtkWidget *row = NULL;
+ GtkWidget *entry = NULL;
+ gchar *title = NULL;
+ const gchar *value = NULL;
+
+ if(pidgin_account_editor_advanced_option_use_default(editor)) {
+ value = purple_account_option_get_default_string(option);
+ } else {
+ const gchar *setting = purple_account_option_get_setting(option);
+ const gchar *def_value = NULL;
+
+ def_value = purple_account_option_get_default_string(option);
+
+ value = purple_account_get_string(editor->account, setting, def_value);
+ }
+
+ /* Create the row and set its title with a mnemonic. */
+ row = adw_action_row_new();
+ g_object_bind_property(editor->advanced_toggle, "active", row, "visible",
+ G_BINDING_SYNC_CREATE);
+ adw_preferences_row_set_use_underline(ADW_PREFERENCES_ROW(row), TRUE);
+ title = g_strdup_printf("_%s", purple_account_option_get_text(option));
+ adw_preferences_row_set_title(ADW_PREFERENCES_ROW(row), title);
+ g_free(title);
+
+ adw_preferences_group_add(ADW_PREFERENCES_GROUP(editor->advanced_group),
+ row);
+
+ /* Add the row to the editor's list of advanced rows. */
+ editor->advanced_rows = g_list_append(editor->advanced_rows, row);
+
+ /* Create the input widget. */
+ if(purple_account_option_string_get_masked(option)) {
+ entry = gtk_password_entry_new();
+ } else {
+ entry = gtk_entry_new();
+ }
+
+ if(value != NULL) {
+ gtk_editable_set_text(GTK_EDITABLE(entry), value);
+ }
+ gtk_widget_set_hexpand(entry, TRUE);
+ gtk_widget_set_valign(entry, GTK_ALIGN_CENTER);
+ adw_action_row_add_suffix(ADW_ACTION_ROW(row), entry);
+ adw_action_row_set_activatable_widget(ADW_ACTION_ROW(row), entry);
+
+ return entry;
+}
+
+static GtkWidget *
+pidgin_account_editor_add_advanced_list(PidginAccountEditor *editor,
+ PurpleAccountOption *option)
+{
+ GtkWidget *row = NULL;
+ GtkStringList *model = NULL;
+ GList *data = NULL;
+ GList *items = NULL;
+ gchar *title = NULL;
+ const gchar *value = FALSE;
+ guint index = 0;
+ guint position = 0;
+
+ if(pidgin_account_editor_advanced_option_use_default(editor)) {
+ value = purple_account_option_get_default_list_value(option);
+ } else {
+ const gchar *setting = purple_account_option_get_setting(option);
+ const gchar *def_value = NULL;
+
+ def_value = purple_account_option_get_default_list_value(option);
+
+ value = purple_account_get_string(editor->account, setting, def_value);
+ }
+
+ /* Create the row and set its title with a mnemonic. */
+ row = adw_combo_row_new();
+ g_object_bind_property(editor->advanced_toggle, "active", row, "visible",
+ G_BINDING_SYNC_CREATE);
+ adw_preferences_row_set_use_underline(ADW_PREFERENCES_ROW(row), TRUE);
+ adw_combo_row_set_use_subtitle(ADW_COMBO_ROW(row), TRUE);
+ title = g_strdup_printf("_%s", purple_account_option_get_text(option));
+ adw_preferences_row_set_title(ADW_PREFERENCES_ROW(row), title);
+ g_free(title);
+
+ adw_preferences_group_add(ADW_PREFERENCES_GROUP(editor->advanced_group),
+ row);
+
+ /* Add the row to the editor's list of advanced rows. */
+ editor->advanced_rows = g_list_append(editor->advanced_rows, row);
+
+ /* Create the model and data for the expression. */
+ items = purple_account_option_get_list(option);
+ model = gtk_string_list_new(NULL);
+
+ for(GList *l = items; l != NULL; l = l->next) {
+ PurpleKeyValuePair *kvp = l->data;
+
+ if(kvp != NULL) {
+ if(purple_strequal(kvp->value, value)) {
+ position = index;
+ }
+
+ data = g_list_append(data, kvp->value);
+ gtk_string_list_append(model, kvp->key);
+ }
+
+ index++;
+ }
+
+ adw_combo_row_set_model(ADW_COMBO_ROW(row), G_LIST_MODEL(model));
+ adw_combo_row_set_selected(ADW_COMBO_ROW(row), position);
+ g_object_set_data_full(G_OBJECT(row), "keys", data,
+ (GDestroyNotify)g_list_free);
+
+ return row;
+}
+
+static void
+pidgin_account_editor_add_advanced_option(PidginAccountEditor *editor,
+ PurpleAccountOption *option)
+{
+ PurplePrefType type;
+ GtkWidget *widget = NULL;
+
+ type = purple_account_option_get_pref_type(option);
+ switch(type) {
+ case PURPLE_PREF_BOOLEAN:
+ widget = pidgin_account_editor_add_advanced_boolean(editor, option);
+ break;
+ case PURPLE_PREF_INT:
+ widget = pidgin_account_editor_add_advanced_int(editor, option);
+ break;
+ case PURPLE_PREF_STRING:
+ widget = pidgin_account_editor_add_advanced_string(editor, option);
+ break;
+ case PURPLE_PREF_STRING_LIST:
+ widget = pidgin_account_editor_add_advanced_list(editor, option);
+ break;
+ default:
+ purple_debug_error("PidginAccountEditor",
+ "Invalid Account Option pref type (%d)", type);
+ break;
+ }
+
+ if(GTK_IS_WIDGET(widget)) {
+ g_object_set_data_full(G_OBJECT(widget), "option", option,
+ (GDestroyNotify)purple_account_option_destroy);
+
+ editor->advanced_entries = g_list_append(editor->advanced_entries,
+ widget);
+ } else {
+ purple_account_option_destroy(option);
+ }
+}
+
+static void
+pidgin_account_editor_update_advanced_options(PidginAccountEditor *editor,
+ PurpleProtocol *protocol)
+{
+ GList *options = NULL;
+
+ g_clear_pointer(&editor->advanced_entries, g_list_free);
+ while(editor->advanced_rows != NULL) {
+ adw_preferences_group_remove(ADW_PREFERENCES_GROUP(editor->advanced_group),
+ GTK_WIDGET(editor->advanced_rows->data));
+
+ editor->advanced_rows = g_list_delete_link(editor->advanced_rows,
+ editor->advanced_rows);
+ }
+
+ if(!PURPLE_IS_PROTOCOL(protocol)) {
+ gtk_widget_set_visible(editor->advanced_group, FALSE);
+
+ return;
+ }
+
+ options = purple_protocol_get_account_options(protocol);
+ if(options == NULL) {
+ gtk_widget_set_visible(editor->advanced_group, FALSE);
+
+ return;
+ }
+
+ /* Iterate the options and call our helper which will take ownership of the
+ * option itself, but we'll delete the list item as we go.
+ */
+ while(options != NULL) {
+ pidgin_account_editor_add_advanced_option(editor, options->data);
+
+ options = g_list_delete_link(options, options);
+ }
+
+ gtk_widget_set_visible(editor->advanced_group, TRUE);
+}
+
+static void
+pidgin_account_editor_update_proxy_options(PidginAccountEditor *editor) {
+ PurpleProxyInfo *info = NULL;
+ GListModel *model = NULL;
+ const gchar *svalue = NULL;
+ gint ivalue = 0;
+ guint position = 0;
+
+ if(!PURPLE_IS_ACCOUNT(editor->account)) {
+ return;
+ }
+
+ info = purple_account_get_proxy_info(editor->account);
+
+ switch(purple_proxy_info_get_proxy_type(info)) {
+ case PURPLE_PROXY_TYPE_USE_GLOBAL:
+ svalue = "global";
+ break;
+ case PURPLE_PROXY_TYPE_NONE:
+ svalue = "none";
+ break;
+ case PURPLE_PROXY_TYPE_SOCKS4:
+ svalue = "socks4";
+ break;
+ case PURPLE_PROXY_TYPE_SOCKS5:
+ svalue = "socks5";
+ break;
+ case PURPLE_PROXY_TYPE_TOR:
+ svalue = "tor";
+ break;
+ case PURPLE_PROXY_TYPE_HTTP:
+ svalue = "http";
+ break;
+ case PURPLE_PROXY_TYPE_USE_ENVVAR:
+ svalue = "envvar";
+ break;
+ }
+
+ model = adw_combo_row_get_model(ADW_COMBO_ROW(editor->proxy_type));
+ for(guint i = 0; i < g_list_model_get_n_items(model); i++) {
+ GtkStringObject *obj = g_list_model_get_item(model, i);
+ if(purple_strequal(svalue, gtk_string_object_get_string(obj))) {
+ position = i;
+ break;
+ }
+ }
+ adw_combo_row_set_selected(ADW_COMBO_ROW(editor->proxy_type), position);
+
+ svalue = purple_proxy_info_get_hostname(info);
+ if(svalue == NULL) {
+ svalue = "";
+ }
+ gtk_editable_set_text(GTK_EDITABLE(editor->proxy_host), svalue);
+
+ ivalue = purple_proxy_info_get_port(info);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(editor->proxy_port),
+ (gdouble)ivalue);
+
+ svalue = purple_proxy_info_get_username(info);
+ if(svalue == NULL) {
+ svalue = "";
+ }
+ gtk_editable_set_text(GTK_EDITABLE(editor->proxy_username), svalue);
+
+ svalue = purple_proxy_info_get_password(info);
+ if(svalue == NULL) {
+ svalue = "";
+ }
+ gtk_editable_set_text(GTK_EDITABLE(editor->proxy_password), svalue);
+}
+
+static void
+pidgin_account_editor_update(PidginAccountEditor *editor) {
+ PurpleProtocol *protocol = NULL;
+ gboolean sensitive = FALSE;
+
+ if(PURPLE_IS_ACCOUNT(editor->account)) {
+ PurpleConnection *connection = NULL;
+
+ connection = purple_account_get_connection(editor->account);
+ if(PURPLE_IS_CONNECTION(connection)) {
+ gtk_widget_set_sensitive(editor->protocol, FALSE);
+ }
+ }
+
+ protocol = pidgin_protocol_chooser_get_protocol(PIDGIN_PROTOCOL_CHOOSER(editor->protocol));
+
+ sensitive = pidgin_account_editor_update_login_options(editor, protocol);
+ pidgin_account_editor_update_user_options(editor, protocol);
+ pidgin_account_editor_update_advanced_options(editor, protocol);
+ pidgin_account_editor_update_proxy_options(editor);
+
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(editor), GTK_RESPONSE_APPLY,
+ sensitive);
+}
+
+static void
+pidgin_account_editor_login_options_update_editable(PidginAccountEditor *editor)
+{
+ PurpleConnection *connection = NULL;
+ gboolean editable = TRUE;
+
+ if(PURPLE_IS_ACCOUNT(editor->account)) {
+
+ connection = purple_account_get_connection(editor->account);
+
+ /* If we have an active connection, we need to disable everything
+ * related to the protocol and username.
+ */
+ if(PURPLE_IS_CONNECTION(connection)) {
+ PidginProtocolChooser *chooser = NULL;
+ PurpleProtocol *connected_protocol = NULL;
+ PurpleProtocol *selected_protocol = NULL;
+ editable = FALSE;
+
+ /* Check if the user changed the protocol. If they did, switch it
+ * back and update the editor to reflect what settings are active.
+ */
+ connected_protocol = purple_connection_get_protocol(connection);
+
+ chooser = PIDGIN_PROTOCOL_CHOOSER(editor->protocol);
+ selected_protocol = pidgin_protocol_chooser_get_protocol(chooser);
+ if(connected_protocol != selected_protocol) {
+ pidgin_protocol_chooser_set_protocol(chooser, connected_protocol);
+ pidgin_account_editor_update(editor);
+ }
+ }
+
+ }
+
+ gtk_widget_set_sensitive(editor->protocol, editable);
+ gtk_editable_set_editable(GTK_EDITABLE(editor->username), editable);
+ for(GList *l = editor->user_split_entries; l != NULL; l = l->next) {
+ GtkWidget *widget = l->data;
+
+ gtk_editable_set_editable(GTK_EDITABLE(widget), editable);
+ }
+}
+
+static void
pidgin_account_editor_set_account(PidginAccountEditor *editor,
PurpleAccount *account)
{
if(g_set_object(&editor->account, account)) {
- PurpleProxyInfo *proxy_info = NULL;
+ if(PURPLE_IS_ACCOUNT(account)) {
+ g_signal_connect(account, "notify::connection",
+ G_CALLBACK(pidgin_account_editor_connection_changed_cb),
+ editor);
+ }
+
+ g_object_notify_by_pspec(G_OBJECT(editor), properties[PROP_ACCOUNT]);
+ }
+
+ pidgin_account_editor_update(editor);
+}
+
+static gboolean
+pidgin_account_editor_save_login_options(PidginAccountEditor *editor) {
+ PurpleProtocol *protocol = NULL;
+ GList *split_item = NULL, *entry_item = NULL;
+ GString *username = NULL;
+ const gchar *protocol_id = NULL;
+ gboolean new_account = FALSE;
- if(PURPLE_IS_ACCOUNT(account)) {
- proxy_info = purple_account_get_proxy_info(account);
+ protocol = pidgin_protocol_chooser_get_protocol(PIDGIN_PROTOCOL_CHOOSER(editor->protocol));
+ protocol_id = purple_protocol_get_id(protocol);
+
+ username = g_string_new(gtk_editable_get_text(GTK_EDITABLE(editor->username)));
+
+ split_item = purple_protocol_get_user_splits(protocol);
+ entry_item = editor->user_split_entries;
+ while(split_item != NULL && entry_item != NULL) {
+ PurpleAccountUserSplit *split = split_item->data;
+ GtkEntry *entry = entry_item->data;
+ const gchar *value = "";
+ gchar sep = '\0';
+
+ sep = purple_account_user_split_get_separator(split);
+ g_string_append_c(username, sep);
+
+ if(GTK_IS_ENTRY(entry)) {
+ value = gtk_editable_get_text(GTK_EDITABLE(entry));
+ }
+
+ if(value == NULL || *value == '\0') {
+ value = purple_account_user_split_get_default_value(split);
}
- pidgin_proxy_options_set_info(PIDGIN_PROXY_OPTIONS(editor->proxy_options),
- proxy_info);
+ g_string_append(username, value);
+
+ split_item = split_item->next;
+ entry_item = entry_item->next;
+ }
+
+ if(!PURPLE_IS_ACCOUNT(editor->account)) {
+ editor->account = purple_account_new(username->str, protocol_id);
+ new_account = TRUE;
+ } else {
+ purple_account_set_username(editor->account, username->str);
+ purple_account_set_protocol_id(editor->account, protocol_id);
+ }
+
+ g_string_free(username, TRUE);
+
+ return new_account;
+}
- g_object_notify_by_pspec(G_OBJECT(editor), properties[PROP_ACCOUNT]);
+static void
+pidgin_account_editor_save_user_options(PidginAccountEditor *editor) {
+ const gchar *svalue = NULL;
+ gboolean bvalue = FALSE;
+
+ /* Set the alias. */
+ svalue = gtk_editable_get_text(GTK_EDITABLE(editor->alias));
+ if(*svalue == '\0') {
+ svalue = NULL;
+ }
+ purple_account_set_private_alias(editor->account, svalue);
+
+ /* Set whether or not to use the global avatar. */
+ bvalue = gtk_switch_get_active(GTK_SWITCH(editor->use_custom_avatar));
+ purple_account_set_bool(editor->account, "use-global-buddyicon", !bvalue);
+
+ if(bvalue) {
+ if(GDK_IS_PIXBUF(editor->avatar_pixbuf)) {
+ # warning implement this when buddy icons do not suck so bad.
+ } else {
+ purple_buddy_icons_set_account_icon(editor->account, NULL, 0);
+ }
+ } else {
+ # warning set the global buddy icon when buddy icons do not suck so bad.
}
}
static void
+pidgin_account_editor_save_advanced_options(PidginAccountEditor *editor) {
+ for(GList *l = editor->advanced_entries; l != NULL; l = l->next) {
+ GtkWidget *widget = l->data;
+ PurpleAccountOption *option = NULL;
+ GList *keys = NULL;
+ const gchar *setting = NULL;
+ const gchar *svalue = NULL;
+ gboolean bvalue = FALSE;
+ gint ivalue = 0;
+ guint selected = 0;
+
+ option = g_object_get_data(G_OBJECT(widget), "option");
+ setting = purple_account_option_get_setting(option);
+
+ switch(purple_account_option_get_pref_type(option)) {
+ case PURPLE_PREF_STRING:
+ svalue = gtk_editable_get_text(GTK_EDITABLE(widget));
+ purple_account_set_string(editor->account, setting, svalue);
+ break;
+ case PURPLE_PREF_INT:
+ svalue = gtk_editable_get_text(GTK_EDITABLE(widget));
+ ivalue = atoi(svalue);
+ purple_account_set_int(editor->account, setting, ivalue);
+ break;
+ case PURPLE_PREF_BOOLEAN:
+ bvalue = gtk_switch_get_active(GTK_SWITCH(widget));
+ purple_account_set_bool(editor->account, setting, bvalue);
+ break;
+ case PURPLE_PREF_STRING_LIST:
+ keys = g_object_get_data(G_OBJECT(widget), "keys");
+ selected = adw_combo_row_get_selected(ADW_COMBO_ROW(widget));
+ svalue = g_list_nth_data(keys, selected);
+ purple_account_set_string(editor->account, setting, svalue);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+pidgin_account_editor_save_proxy(PidginAccountEditor *editor,
+ gboolean new_account)
+{
+ PurpleProxyInfo *info = NULL;
+ PurpleProxyType type = PURPLE_PROXY_TYPE_NONE;
+ GObject *item = NULL;
+ const gchar *svalue = NULL;
+ gint ivalue = 0;
+
+ /* Build the ProxyInfo object */
+ if(new_account) {
+ info = purple_proxy_info_new();
+ purple_account_set_proxy_info(editor->account, info);
+ } else {
+ info = purple_account_get_proxy_info(editor->account);
+ }
+
+ item = adw_combo_row_get_selected_item(ADW_COMBO_ROW(editor->proxy_type));
+ svalue = gtk_string_object_get_string(GTK_STRING_OBJECT(item));
+ if(purple_strequal(svalue, "global")) {
+ type = PURPLE_PROXY_TYPE_USE_GLOBAL;
+ } else if(purple_strequal(svalue, "none")) {
+ type = PURPLE_PROXY_TYPE_NONE;
+ } else if(purple_strequal(svalue, "socks4")) {
+ type = PURPLE_PROXY_TYPE_SOCKS4;
+ } else if(purple_strequal(svalue, "socks5")) {
+ type = PURPLE_PROXY_TYPE_SOCKS5;
+ } else if(purple_strequal(svalue, "tor")) {
+ type = PURPLE_PROXY_TYPE_TOR;
+ } else if(purple_strequal(svalue, "http")) {
+ type = PURPLE_PROXY_TYPE_HTTP;
+ } else if(purple_strequal(svalue, "envvar")) {
+ type = PURPLE_PROXY_TYPE_USE_ENVVAR;
+ }
+ purple_proxy_info_set_proxy_type(info, type);
+
+ svalue = gtk_editable_get_text(GTK_EDITABLE(editor->proxy_host));
+ purple_proxy_info_set_hostname(info, svalue);
+
+ ivalue = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(editor->proxy_port));
+ purple_proxy_info_set_port(info, ivalue);
+
+ svalue = gtk_editable_get_text(GTK_EDITABLE(editor->proxy_username));
+ purple_proxy_info_set_username(info, svalue);
+
+ svalue = gtk_editable_get_text(GTK_EDITABLE(editor->proxy_password));
+ purple_proxy_info_set_password(info, svalue);
+}
+
+static void
pidgin_account_editor_save_account(PidginAccountEditor *editor) {
- PurpleAccountManager *manager = NULL;
- PurpleProxyInfo *info = NULL;
gboolean new_account = FALSE;
- manager = purple_account_manager_get_default();
-
- if(!PURPLE_IS_ACCOUNT(editor->account)) {
- editor->account = purple_account_new("undefined", "undefined");
- new_account = TRUE;
- }
-
- info = pidgin_proxy_options_get_info(PIDGIN_PROXY_OPTIONS(editor->proxy_options));
- purple_account_set_proxy_info(editor->account, info);
+ new_account = pidgin_account_editor_save_login_options(editor);
+ pidgin_account_editor_save_user_options(editor);
+ pidgin_account_editor_save_advanced_options(editor);
+ pidgin_account_editor_save_proxy(editor, new_account);
/* If this is a new account, add it to the account manager and bring it
* online.
*/
if(new_account) {
+ PurpleAccountManager *manager = NULL;
const PurpleSavedStatus *saved_status;
+ manager = purple_account_manager_get_default();
+
purple_account_manager_add(manager, editor->account);
saved_status = purple_savedstatus_get_current();
@@ -100,6 +915,16 @@
* Callbacks
*****************************************************************************/
static void
+pidgin_account_editor_connection_changed_cb(G_GNUC_UNUSED GObject *obj,
+ G_GNUC_UNUSED GParamSpec *pspec,
+ gpointer data)
+{
+ PidginAccountEditor *editor = data;
+
+ pidgin_account_editor_login_options_update_editable(editor);
+}
+
+static void
pidgin_account_editor_response_cb(GtkDialog *dialog, gint response_id,
G_GNUC_UNUSED gpointer data)
{
@@ -110,6 +935,141 @@
gtk_window_destroy(GTK_WINDOW(dialog));
}
+static void
+pidgin_account_editor_protocol_changed_cb(G_GNUC_UNUSED GObject *obj,
+ G_GNUC_UNUSED GParamSpec *pspec,
+ gpointer data)
+{
+ pidgin_account_editor_update(data);
+}
+
+static void
+pidgin_account_editor_username_changed_cb(GtkEditable *self, gpointer data) {
+ PidginAccountEditor *editor = data;
+ const gchar *text = gtk_editable_get_text(self);
+ gboolean sensitive = FALSE;
+
+ if(text != NULL && *text != '\0') {
+ sensitive = TRUE;
+ }
+
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(editor), GTK_RESPONSE_APPLY,
+ sensitive);
+}
+
+static void
+pidgin_account_editor_avatar_response_cb(GtkNativeDialog *self,
+ gint response_id, gpointer data)
+{
+ PidginAccountEditor *editor = data;
+
+ if(response_id == GTK_RESPONSE_ACCEPT) {
+ GError *error = NULL;
+ GFile *file = NULL;
+ gchar *filename = NULL;
+
+ file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(self));
+ filename = g_file_get_path(file);
+
+ g_clear_object(&editor->avatar_pixbuf);
+ editor->avatar_pixbuf = gdk_pixbuf_new_from_file(filename, &error);
+ if(error != NULL) {
+ g_warning("Failed to create pixbuf from file %s: %s", filename,
+ error->message);
+ g_clear_error(&error);
+ } else {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(editor->avatar),
+ editor->avatar_pixbuf);
+ }
+
+ g_free(filename);
+ g_object_unref(file);
+ }
+
+ g_clear_object(&editor->avatar_dialog);
+}
+
+static void
+pidgin_account_editor_avatar_set_clicked_cb(G_GNUC_UNUSED GtkButton *self,
+ gpointer data)
+{
+ PidginAccountEditor *editor = data;
+
+ editor->avatar_dialog = gtk_file_chooser_native_new(_("Buddy Icon"),
+ GTK_WINDOW(editor),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ _("_Open"),
+ _("_Cancel"));
+ gtk_native_dialog_set_transient_for(GTK_NATIVE_DIALOG(editor->avatar_dialog),
+ GTK_WINDOW(editor));
+
+ g_signal_connect(G_OBJECT(editor->avatar_dialog), "response",
+ G_CALLBACK(pidgin_account_editor_avatar_response_cb),
+ editor);
+
+ gtk_native_dialog_show(GTK_NATIVE_DIALOG(editor->avatar_dialog));
+}
+
+static void
+pidgin_account_editor_avatar_remove_clicked_cb(G_GNUC_UNUSED GtkButton *self,
+ gpointer data)
+{
+ PidginAccountEditor *editor = data;
+
+ gtk_image_set_from_icon_name(GTK_IMAGE(editor->avatar), "select-avatar");
+
+ g_clear_object(&editor->avatar_pixbuf);
+}
+
+static gchar *
+pidgin_account_editor_proxy_type_expression_cb(GObject *self,
+ G_GNUC_UNUSED gpointer data)
+{
+ const gchar *text = "";
+ const gchar *value = NULL;
+
+ value = gtk_string_object_get_string(GTK_STRING_OBJECT(self));
+ if(purple_strequal(value, "global")) {
+ text = _("Use Global Proxy Settings");
+ } else if(purple_strequal(value, "none")) {
+ text = _("No proxy");
+ } else if(purple_strequal(value, "socks4")) {
+ text = _("SOCKS 4");
+ } else if(purple_strequal(value, "socks5")) {
+ text = _("SOCKS 5");
+ } else if(purple_strequal(value, "tor")) {
+ text = _("Tor/Privacy (SOCKS 5)");
+ } else if(purple_strequal(value, "http")) {
+ text = _("HTTP");
+ } else if(purple_strequal(value, "envvar")) {
+ text = _("Use Environmental Settings");
+ }
+
+ return g_strdup(text);
+}
+
+static void
+pidgin_account_editor_proxy_type_changed_cb(G_GNUC_UNUSED GObject *obj,
+ G_GNUC_UNUSED GParamSpec *pspec,
+ gpointer data)
+{
+ PidginAccountEditor *editor = data;
+ GObject *selected = NULL;
+ gboolean show_options = TRUE;
+ const gchar *value = NULL;
+
+ selected = adw_combo_row_get_selected_item(ADW_COMBO_ROW(editor->proxy_type));
+ value = gtk_string_object_get_string(GTK_STRING_OBJECT(selected));
+
+ if(purple_strequal(value, "global") || purple_strequal(value, "none") ||
+ purple_strequal(value, "envvar"))
+ {
+ show_options = FALSE;
+ }
+
+ gtk_widget_set_visible(editor->proxy_options, show_options);
+}
+
/******************************************************************************
* GObject Implementation
*****************************************************************************/
@@ -154,15 +1114,60 @@
PidginAccountEditor *editor = PIDGIN_ACCOUNT_EDITOR(obj);
g_clear_object(&editor->account);
+ g_clear_object(&editor->avatar_dialog);
+ g_clear_object(&editor->avatar_pixbuf);
G_OBJECT_CLASS(pidgin_account_editor_parent_class)->dispose(obj);
}
static void
-pidgin_account_editor_init(PidginAccountEditor *account_editor) {
- GtkWidget *widget = GTK_WIDGET(account_editor);
+pidgin_account_editor_init(PidginAccountEditor *editor) {
+ GtkCssProvider *css_provider = NULL;
+ GtkStyleContext *context = NULL;
+ GtkWidget *widget = GTK_WIDGET(editor);
gtk_widget_init_template(widget);
+
+ css_provider = gtk_css_provider_new();
+ gtk_css_provider_load_from_resource(css_provider,
+ "/im/pidgin/Pidgin3/Accounts/entry.css");
+
+ context = gtk_widget_get_style_context(GTK_WIDGET(editor));
+ gtk_style_context_add_provider(context,
+ GTK_STYLE_PROVIDER(css_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ g_clear_object(&css_provider);
+
+ pidgin_account_editor_proxy_type_changed_cb(NULL, NULL, editor);
+}
+
+static void
+pidgin_account_editor_constructed(GObject *obj) {
+ PidginAccountEditor *editor = PIDGIN_ACCOUNT_EDITOR(obj);
+
+ G_OBJECT_CLASS(pidgin_account_editor_parent_class)->constructed(obj);
+
+ if(PURPLE_IS_ACCOUNT(editor->account)) {
+ pidgin_protocol_chooser_set_protocol(PIDGIN_PROTOCOL_CHOOSER(editor->protocol),
+ purple_account_get_protocol(editor->account));
+ }
+
+ pidgin_account_editor_update(editor);
+ pidgin_account_editor_login_options_update_editable(editor);
+}
+
+static void
+pidgin_account_editor_finalize(GObject *obj) {
+ PidginAccountEditor *editor = PIDGIN_ACCOUNT_EDITOR(obj);
+
+ g_clear_pointer(&editor->user_split_entries, g_list_free);
+ g_clear_pointer(&editor->user_split_rows, g_list_free);
+
+ g_clear_pointer(&editor->advanced_entries, g_list_free);
+ g_clear_pointer(&editor->advanced_rows, g_list_free);
+
+ G_OBJECT_CLASS(pidgin_account_editor_parent_class)->finalize(obj);
}
static void
@@ -172,7 +1177,9 @@
obj_class->get_property = pidgin_account_editor_get_property;
obj_class->set_property = pidgin_account_editor_set_property;
+ obj_class->constructed = pidgin_account_editor_constructed;
obj_class->dispose = pidgin_account_editor_dispose;
+ obj_class->finalize = pidgin_account_editor_finalize;
/**
* PidginAccountEditor::account:
@@ -192,13 +1199,62 @@
gtk_widget_class_set_template_from_resource(widget_class,
"/im/pidgin/Pidgin3/Accounts/editor.ui");
+ /* Dialog */
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_account_editor_response_cb);
+
+ /* Login Options */
gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
- notebook);
+ login_options);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ protocol);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ username);
+
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_account_editor_protocol_changed_cb);
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_account_editor_username_changed_cb);
+
+ /* User Options */
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ alias);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ avatar_row);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ use_custom_avatar);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ avatar);
+
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_account_editor_avatar_set_clicked_cb);
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_account_editor_avatar_remove_clicked_cb);
+
+ /* Advanced Options */
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ advanced_group);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ advanced_toggle);
+
+ /* Proxy Options */
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ proxy_type);
gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
proxy_options);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ proxy_host);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ proxy_port);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ proxy_username);
+ gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
+ proxy_password);
gtk_widget_class_bind_template_callback(widget_class,
- pidgin_account_editor_response_cb);
+ pidgin_account_editor_proxy_type_expression_cb);
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_account_editor_proxy_type_changed_cb);
}
/******************************************************************************
--- a/pidgin/resources/Accounts/editor.ui Thu Sep 15 20:59:06 2022 -0500
+++ b/pidgin/resources/Accounts/editor.ui Thu Sep 15 22:32:05 2022 -0500
@@ -19,6 +19,7 @@
-->
<interface>
+ <requires lib="Adw" version="1.0"/>
<requires lib="gtk" version="4.0"/>
<requires lib="pidgin" version="3.0"/>
<!-- interface-license-type gplv2 -->
@@ -26,35 +27,230 @@
<!-- interface-description Internet Messenger -->
<!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
<template class="PidginAccountEditor" parent="GtkDialog">
+ <property name="resizable">0</property>
+ <property name="default-height">600</property>
+ <property name="default-width">400</property>
+ <property name="title" translatable="1">Edit Account</property>
<signal name="response" handler="pidgin_account_editor_response_cb" swapped="no"/>
<child internal-child="content_area">
<object class="GtkBox">
- <property name="orientation">vertical</property>
- <property name="spacing">2</property>
+ <property name="vexpand">1</property>
<child>
- <object class="GtkNotebook" id="notebook">
- <property name="focusable">1</property>
- <child>
- <object class="GtkNotebookPage">
- <property name="position">0</property>
- <property name="child">
- <object class="PidginProxyOptions" id="proxy_options">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
+ <object class="GtkScrolledWindow">
+ <property name="vexpand">1</property>
+ <property name="hexpand">1</property>
+ <property name="child">
+ <object class="AdwPreferencesPage">
+ <property name="vexpand">1</property>
+ <property name="hexpand">1</property>
+ <child>
+ <object class="AdwPreferencesGroup" id="login_options">
+ <property name="title" translatable="1">Login Options</property>
+ <child>
+ <object class="AdwActionRow">
+ <property name="activatable-widget">protocol</property>
+ <property name="title" translatable="1">Pro_tocol</property>
+ <property name="use-underline">1</property>
+ <child>
+ <object class="PidginProtocolChooser" id="protocol">
+ <property name="hexpand">1</property>
+ <property name="valign">center</property>
+ <signal name="notify::protocol" handler="pidgin_account_editor_protocol_changed_cb" object="PidginAccountEditor" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwActionRow">
+ <property name="activatable-widget">username</property>
+ <property name="title" translatable="1">_Username</property>
+ <property name="use-underline">1</property>
+ <child>
+ <object class="GtkEntry" id="username">
+ <property name="hexpand">1</property>
+ <property name="valign">center</property>
+ <property name="truncate-multiline">1</property>
+ <signal name="changed" handler="pidgin_account_editor_username_changed_cb" object="PidginAccountEditor" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <property name="title" translatable="1">User Options</property>
+ <child>
+ <object class="AdwActionRow">
+ <property name="activatable-widget">alias</property>
+ <property name="title" translatable="1">_Local alias</property>
+ <property name="use-underline">1</property>
+ <child>
+ <object class="GtkEntry" id="alias">
+ <property name="truncate-multiline">1</property>
+ <property name="hexpand">1</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwActionRow" id="avatar_row">
+ <property name="activatable-widget">avatar</property>
+ <property name="title" translatable="1">Use custom _avatar</property>
+ <property name="use-underline">1</property>
+ <property name="visible">0</property>
+ <child type="prefix">
+ <object class="GtkSwitch" id="use_custom_avatar">
+ <property name="valign">center</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="valign">center</property>
+ <binding name="sensitive">
+ <lookup name="active">use_custom_avatar</lookup>
+ </binding>
+ <child>
+ <object class="GtkImage" id="avatar">
+ <property name="icon-name">select-avatar</property>
+ <property name="icon-size">large</property>
+ </object>
+ </child>
+ <signal name="clicked" handler="pidgin_account_editor_avatar_set_clicked_cb" object="PidginAccountEditor" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="remove">
+ <property name="label" translatable="1">_Remove</property>
+ <property name="use-underline">1</property>
+ <property name="valign">center</property>
+ <binding name="sensitive">
+ <lookup name="active">use_custom_avatar</lookup>
+ </binding>
+ <signal name="clicked" handler="pidgin_account_editor_avatar_remove_clicked_cb" object="PidginAccountEditor" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
- </property>
- <property name="tab">
- <object class="GtkLabel">
- <property name="label" translatable="1">_Proxy</property>
- <property name="use-underline">1</property>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup" id="advanced_group">
+ <property name="title" translatable="1">Advanced Options</property>
+ <property name="description" translatable="1">Additional options for this account.</property>
+ <property name="visible">0</property>
+ <child type="header-suffix">
+ <object class="GtkSwitch" id="advanced_toggle">
+ <property name="active">0</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
</object>
- </property>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <property name="title" translatable="1">Proxy</property>
+ <child>
+ <object class="AdwComboRow" id="proxy_type">
+ <property name="title" translatable="1">Proxy t_ype</property>
+ <property name="use-underline">1</property>
+ <property name="use-subtitle">1</property>
+ <property name="model">
+ <object class="GtkStringList">
+ <items>
+ <item>global</item>
+ <item>none</item>
+ <item>socks4</item>
+ <item>socks5</item>
+ <item>tor</item>
+ <item>http</item>
+ <item>envvar</item>
+ </items>
+ </object>
+ </property>
+ <property name="expression">
+ <closure type="gchararray" function="pidgin_account_editor_proxy_type_expression_cb"/>
+ </property>
+ <signal name="notify::selected" handler="pidgin_account_editor_proxy_type_changed_cb" object="PidginAccountEditor" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesRow" id="proxy_options">
+ <property name="visible">0</property>
+ <child>
+ <object class="GtkListBox">
+ <child>
+ <object class="AdwActionRow">
+ <property name="activatable-widget">proxy_host</property>
+ <property name="title" translatable="1">_Host</property>
+ <property name="use-underline">1</property>
+ <child>
+ <object class="GtkEntry" id="proxy_host">
+ <property name="hexpand">1</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwActionRow">
+ <property name="activatable-widget">proxy_port</property>
+ <property name="title" translatable="1">P_ort</property>
+ <property name="use-underline">1</property>
+ <child>
+ <object class="GtkSpinButton" id="proxy_port">
+ <property name="text" translatable="1">0</property>
+ <property name="adjustment">
+ <object class="GtkAdjustment">
+ <property name="upper">65535</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ </property>
+ <property name="numeric">1</property>
+ <property name="hexpand">1</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwActionRow">
+ <property name="activatable-widget">proxy_username</property>
+ <property name="title" translatable="1">User_name</property>
+ <property name="use-underline">1</property>
+ <child>
+ <object class="GtkEntry" id="proxy_username">
+ <property name="hexpand">1</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwActionRow">
+ <property name="activatable-widget">proxy_password</property>
+ <property name="title" translatable="1">Pa_ssword</property>
+ <property name="use-underline">1</property>
+ <child>
+ <object class="GtkPasswordEntry" id="proxy_password">
+ <property name="hexpand">1</property>
+ <property name="show-peek-icon">1</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
- </child>
+ </property>
</object>
</child>
</object>
@@ -62,7 +258,6 @@
<child type="action">
<object class="GtkButton" id="button1">
<property name="label" translatable="1">_Cancel</property>
- <property name="focusable">1</property>
<property name="receives-default">1</property>
<property name="use-underline">1</property>
</object>
@@ -70,8 +265,8 @@
<child type="action">
<object class="GtkButton" id="button2">
<property name="label" translatable="1">_Save</property>
- <property name="focusable">1</property>
<property name="receives-default">1</property>
+ <property name="sensitive">0</property>
<property name="use-underline">1</property>
</object>
</child>