Mon, 02 May 2022 23:43:16 -0500
Create a PidginProxyOptions widget
This replaces the old page in the account editor and uses a PurpleProxyInfo
object to for editing.
Testing Done:
Verified it populated saved values on an existing account, as well as saved values on existing account.
Also verified that you can create a new account with proxy options and that they're saved.
Reviewed at https://reviews.imfreedom.org/r/1377/
--- a/pidgin/gtkaccount.c Mon May 02 21:57:35 2022 -0500 +++ b/pidgin/gtkaccount.c Mon May 02 23:43:16 2022 -0500 @@ -36,6 +36,7 @@ #include "pidgindialog.h" #include "minidialog.h" #include "pidginprotocolchooser.h" +#include "pidginproxyoptions.h" enum { @@ -92,8 +93,6 @@ char *protocol_id; PurpleProtocol *protocol; - PurpleProxyType new_proxy_type; - GList *user_split_entries; GList *protocol_opt_entries; @@ -126,14 +125,7 @@ /* Protocol Options */ GtkWidget *protocol_frame; - /* Proxy Options */ - GtkWidget *proxy_frame; - GtkWidget *proxy_vbox; - GtkWidget *proxy_dropdown; - GtkWidget *proxy_host_entry; - GtkWidget *proxy_port_entry; - GtkWidget *proxy_user_entry; - GtkWidget *proxy_pass_entry; + GtkWidget *proxy_options; /* Voice & Video Options*/ GtkWidget *voice_frame; @@ -159,7 +151,6 @@ static void add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_account_options(AccountPrefsDialog *dialog); -static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_voice_options(AccountPrefsDialog *dialog); static GtkWidget * @@ -917,210 +908,6 @@ g_list_free_full(opts, (GDestroyNotify)purple_account_option_destroy); } -static GtkWidget * -make_proxy_dropdown(void) -{ - GtkWidget *dropdown; - GtkListStore *model; - GtkTreeIter iter; - GtkCellRenderer *renderer; - - model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); - dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - 0, purple_running_gnome() ? _("Use GNOME Proxy Settings") - :_("Use Global Proxy Settings"), - 1, PURPLE_PROXY_TYPE_USE_GLOBAL, - -1); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - 0, _("No Proxy"), - 1, PURPLE_PROXY_TYPE_NONE, - -1); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - 0, _("SOCKS 4"), - 1, PURPLE_PROXY_TYPE_SOCKS4, - -1); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - 0, _("SOCKS 5"), - 1, PURPLE_PROXY_TYPE_SOCKS5, - -1); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - 0, _("Tor/Privacy (SOCKS5)"), - 1, PURPLE_PROXY_TYPE_TOR, - -1); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - 0, _("HTTP"), - 1, PURPLE_PROXY_TYPE_HTTP, - -1); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - 0, _("Use Environmental Settings"), - 1, PURPLE_PROXY_TYPE_USE_ENVVAR, - -1); - - renderer = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer, - "text", 0, NULL); - - return dropdown; -} - -static void -proxy_type_changed_cb(GtkWidget *menu, AccountPrefsDialog *dialog) -{ - GtkTreeIter iter; - - if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(menu), &iter)) { - int int_value; - gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(menu)), &iter, - 1, &int_value, -1); - dialog->new_proxy_type = int_value; - } - - if (dialog->new_proxy_type == PURPLE_PROXY_TYPE_USE_GLOBAL || - dialog->new_proxy_type == PURPLE_PROXY_TYPE_NONE || - dialog->new_proxy_type == PURPLE_PROXY_TYPE_USE_ENVVAR) { - - gtk_widget_hide(dialog->proxy_vbox); - } - else - gtk_widget_show_all(dialog->proxy_vbox); -} - -static void -port_popup_cb(GtkWidget *w, GtkMenu *menu, gpointer data) -{ - GtkWidget *item1; - GtkWidget *item2; - - /* This is an easter egg. - It means one of two things, both intended as humourus: - A) your network is really slow and you have nothing better to do than - look at butterflies. - B)You are looking really closely at something that shouldn't matter. */ - item1 = gtk_menu_item_new_with_label(_("If you look real closely")); - - /* This is an easter egg. See the comment on the previous line in the source. */ - item2 = gtk_menu_item_new_with_label(_("you can see the butterflies mating")); - - gtk_widget_show(item1); - gtk_widget_show(item2); - - /* Prepend these in reverse order so they appear correctly. */ - gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item2); - gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item1); -} - -static void -add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent) -{ - PurpleProxyInfo *proxy_info; - GtkWidget *vbox; - GtkWidget *vbox2; - GtkTreeIter iter; - GtkTreeModel *proxy_model; - - if (dialog->proxy_frame != NULL) - gtk_widget_destroy(dialog->proxy_frame); - - /* Main vbox */ - dialog->proxy_frame = vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_container_add(GTK_CONTAINER(parent), vbox); - gtk_widget_show(vbox); - - /* Proxy Type drop-down. */ - dialog->proxy_dropdown = make_proxy_dropdown(); - - add_pref_box(dialog, vbox, _("Proxy _type:"), dialog->proxy_dropdown); - - /* Setup the second vbox, which may be hidden at times. */ - dialog->proxy_vbox = vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 12); - gtk_widget_show(vbox2); - - /* Host */ - dialog->proxy_host_entry = gtk_entry_new(); - add_pref_box(dialog, vbox2, _("_Host:"), dialog->proxy_host_entry); - - /* Port */ - dialog->proxy_port_entry = gtk_entry_new(); - add_pref_box(dialog, vbox2, _("_Port:"), dialog->proxy_port_entry); - - g_signal_connect(G_OBJECT(dialog->proxy_port_entry), "populate-popup", - G_CALLBACK(port_popup_cb), NULL); - - /* User */ - dialog->proxy_user_entry = gtk_entry_new(); - - add_pref_box(dialog, vbox2, _("_Username:"), dialog->proxy_user_entry); - - /* Password */ - dialog->proxy_pass_entry = gtk_entry_new(); - gtk_entry_set_visibility(GTK_ENTRY(dialog->proxy_pass_entry), FALSE); - add_pref_box(dialog, vbox2, _("Pa_ssword:"), dialog->proxy_pass_entry); - - if (dialog->account != NULL && - (proxy_info = purple_account_get_proxy_info(dialog->account)) != NULL) { - const char *value; - int int_val; - - dialog->new_proxy_type = purple_proxy_info_get_proxy_type(proxy_info); - - if ((value = purple_proxy_info_get_hostname(proxy_info)) != NULL) - gtk_entry_set_text(GTK_ENTRY(dialog->proxy_host_entry), value); - - if ((int_val = purple_proxy_info_get_port(proxy_info)) != 0) { - char buf[11]; - - g_snprintf(buf, sizeof(buf), "%d", int_val); - - gtk_entry_set_text(GTK_ENTRY(dialog->proxy_port_entry), buf); - } - - if ((value = purple_proxy_info_get_username(proxy_info)) != NULL) - gtk_entry_set_text(GTK_ENTRY(dialog->proxy_user_entry), value); - - if ((value = purple_proxy_info_get_password(proxy_info)) != NULL) - gtk_entry_set_text(GTK_ENTRY(dialog->proxy_pass_entry), value); - - } else - dialog->new_proxy_type = PURPLE_PROXY_TYPE_USE_GLOBAL; - - proxy_model = gtk_combo_box_get_model( - GTK_COMBO_BOX(dialog->proxy_dropdown)); - if (gtk_tree_model_get_iter_first(proxy_model, &iter)) { - int int_val; - do { - gtk_tree_model_get(proxy_model, &iter, 1, &int_val, -1); - if (int_val == dialog->new_proxy_type) { - gtk_combo_box_set_active_iter( - GTK_COMBO_BOX(dialog->proxy_dropdown), &iter); - break; - } - } while(gtk_tree_model_iter_next(proxy_model, &iter)); - } - - proxy_type_changed_cb(dialog->proxy_dropdown, dialog); - - /* Connect signals. */ - g_signal_connect(G_OBJECT(dialog->proxy_dropdown), "changed", - G_CALLBACK(proxy_type_changed_cb), dialog); -} - static void add_voice_options(AccountPrefsDialog *dialog) { @@ -1372,63 +1159,8 @@ } } - /* Set the proxy stuff. */ - proxy_info = purple_account_get_proxy_info(account); - - /* Create the proxy info if it doesn't exist. */ - if (proxy_info == NULL) { - proxy_info = purple_proxy_info_new(); - purple_account_set_proxy_info(account, proxy_info); - } else { - /* Add a reference to make sure the proxy info stays around. */ - g_object_ref(proxy_info); - } - - /* Set the proxy info type. */ - purple_proxy_info_set_proxy_type(proxy_info, dialog->new_proxy_type); - - /* Host */ - value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_host_entry)); - - if (*value != '\0') - purple_proxy_info_set_hostname(proxy_info, value); - else - purple_proxy_info_set_hostname(proxy_info, NULL); - - /* Port */ - value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_port_entry)); - - if (*value != '\0') - purple_proxy_info_set_port(proxy_info, atoi(value)); - else - purple_proxy_info_set_port(proxy_info, 0); - - /* Username */ - value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_user_entry)); - - if (*value != '\0') - purple_proxy_info_set_username(proxy_info, value); - else - purple_proxy_info_set_username(proxy_info, NULL); - - /* Password */ - value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_pass_entry)); - - if (*value != '\0') - purple_proxy_info_set_password(proxy_info, value); - else - purple_proxy_info_set_password(proxy_info, NULL); - - /* If there are no values set then proxy_info NULL */ - if ((purple_proxy_info_get_proxy_type(proxy_info) == PURPLE_PROXY_TYPE_USE_GLOBAL) && - (purple_proxy_info_get_hostname(proxy_info) == NULL) && - (purple_proxy_info_get_port(proxy_info) == 0) && - (purple_proxy_info_get_username(proxy_info) == NULL) && - (purple_proxy_info_get_password(proxy_info) == NULL)) - { - purple_account_set_proxy_info(account, NULL); - g_clear_object(&proxy_info); - } + proxy_info = pidgin_proxy_options_get_info(PIDGIN_PROXY_OPTIONS(dialog->proxy_options)); + purple_account_set_proxy_info(account, proxy_info); /* Voice and Video settings */ if (dialog->voice_frame) { @@ -1459,8 +1191,6 @@ /* We no longer need the data from the dialog window */ account_win_destroy_cb(NULL, NULL, dialog); - - g_clear_object(&proxy_info); } static void @@ -1488,7 +1218,6 @@ GtkWidget *win; GtkWidget *main_vbox; GtkWidget *vbox; - GtkWidget *dbox; GtkWidget *notebook; GtkWidget *button; @@ -1564,13 +1293,15 @@ /* Setup the page with 'Advanced' (protocol options). */ add_account_options(dialog); - /* Setup the page with 'Proxy'. */ - dbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_container_set_border_width(GTK_CONTAINER(dbox), 12); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dbox, - gtk_label_new_with_mnemonic(_("P_roxy"))); - gtk_widget_show(dbox); - add_proxy_options(dialog, dbox); + /* Setup the proxy options page. */ + dialog->proxy_options = pidgin_proxy_options_new(); + if(PURPLE_IS_ACCOUNT(dialog->account)) { + pidgin_proxy_options_set_info(PIDGIN_PROXY_OPTIONS(dialog->proxy_options), + purple_account_get_proxy_info(dialog->account)); + } + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dialog->proxy_options, + gtk_label_new_with_mnemonic(_("Proxy"))); + gtk_widget_show(dialog->proxy_options); add_voice_options(dialog);
--- a/pidgin/meson.build Mon May 02 21:57:35 2022 -0500 +++ b/pidgin/meson.build Mon May 02 23:43:16 2022 -0500 @@ -50,6 +50,7 @@ 'pidginpresenceicon.c', 'pidginprotocolchooser.c', 'pidginprotocolstore.c', + 'pidginproxyoptions.c', 'pidginscrollbook.c', 'pidginstatusbox.c', 'pidginstatusmanager.c', @@ -113,6 +114,7 @@ 'pidginpresenceicon.h', 'pidginprotocolchooser.h', 'pidginprotocolstore.h', + 'pidginproxyoptions.h', 'pidginscrollbook.h', 'pidginstatusbox.h', 'pidginstatusmanager.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pidginproxyoptions.c Mon May 02 23:43:16 2022 -0500 @@ -0,0 +1,463 @@ +/* + * Pidgin - Internet Messenger + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * + * Pidgin is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#include <glib/gi18n.h> + +#include "pidginproxyoptions.h" + +#include "gtkaccount.h" +#include "pidgincore.h" + +struct _PidginProxyOptions { + GtkBox parent; + + gboolean show_global; + PurpleProxyInfo *info; + + GtkListStore *model; + GtkTreeModelFilter *filter; + + GtkWidget *proxy_type; + + GtkWidget *options; + GtkWidget *hostname; + GtkWidget *port; + GtkWidget *username; + GtkWidget *password; +}; + +enum { + PROP_0, + PROP_SHOW_GLOBAL, + PROP_INFO, + N_PROPERTIES +}; +static GParamSpec *properties[N_PROPERTIES] = {NULL, }; + +enum { + COLUMN_TYPE, + COLUMN_TITLE, +}; + +G_DEFINE_TYPE(PidginProxyOptions, pidgin_proxy_options, GTK_TYPE_BOX) + +/****************************************************************************** + * Helpers + *****************************************************************************/ +static gboolean +pidgin_proxy_options_null_to_empty_str(G_GNUC_UNUSED GBinding *binding, + const GValue *from_value, + GValue *to_value, + G_GNUC_UNUSED gpointer data) +{ + const gchar *str_val = g_value_get_string(from_value); + + if(str_val == NULL) { + str_val = ""; + } + + g_value_set_string(to_value, str_val); + + return TRUE; +} + +static gboolean +pidgin_proxy_options_empty_str_to_null(G_GNUC_UNUSED GBinding *binding, + const GValue *from_value, + GValue *to_value, + G_GNUC_UNUSED gpointer data) +{ + const gchar *str_val = g_value_get_string(from_value); + + if(str_val != NULL && *str_val == '\0') { + str_val = NULL; + } + + g_value_set_string(to_value, str_val); + + return TRUE; +} + +static gboolean +pidgin_proxy_options_gint_to_double(G_GNUC_UNUSED GBinding *binding, + const GValue *from_value, GValue *to_value, + G_GNUC_UNUSED gpointer data) +{ + g_value_set_double(to_value, (gdouble)g_value_get_int(from_value)); + + return TRUE; +} + +static gboolean +pidgin_proxy_options_double_to_gint(G_GNUC_UNUSED GBinding *binding, + const GValue *from_value, GValue *to_value, + G_GNUC_UNUSED gpointer user_data) +{ + g_value_set_int(to_value, (gint)g_value_get_double(from_value)); + + return TRUE; +} + +static gboolean +pidgin_proxy_options_filter_visible(GtkTreeModel *model, GtkTreeIter *iter, + gpointer data) +{ + PidginProxyOptions *options = data; + PurpleProxyType type; + + gtk_tree_model_get(model, iter, COLUMN_TYPE, &type, -1); + + if(type == PURPLE_PROXY_TYPE_USE_GLOBAL) { + return options->show_global; + } + + return TRUE; +} + +/****************************************************************************** + * Callbacks + *****************************************************************************/ +static void +pidgin_proxy_options_proxy_type_changed_cb(GtkComboBox *box, gpointer data) { + PidginProxyOptions *options = data; + PurpleProxyType type; + GtkTreeIter iter; + gboolean sensitive = TRUE; + + if(!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(options->proxy_type), &iter)) { + return; + } + + gtk_tree_model_get(GTK_TREE_MODEL(options->filter), &iter, + COLUMN_TYPE, &type, + -1); + + purple_proxy_info_set_proxy_type(options->info, type); + + switch(type) { + case PURPLE_PROXY_TYPE_USE_GLOBAL: + case PURPLE_PROXY_TYPE_NONE: + case PURPLE_PROXY_TYPE_USE_ENVVAR: + sensitive = FALSE; + break; + default: + break; + } + + gtk_widget_set_sensitive(options->options, sensitive); +} + +static void +pidgin_proxy_options_ports_popup_cb(G_GNUC_UNUSED GtkEntry *entry, + GtkWidget *widget, + G_GNUC_UNUSED gpointer data) +{ + GtkWidget *item = NULL; + + /* This is an easter egg. The items are in reverse order because they are + * prepended to the menu. + * + * It means one of two things, both intended as humorous: + * A) your network is really slow and you have nothing better to do than + * look at butterflies. + * B) You are looking really closely at something that shouldn't matter. + */ + + item = gtk_menu_item_new_with_label(_("you can see the butterflies mating")); + gtk_menu_shell_prepend(GTK_MENU_SHELL(widget), item); + gtk_widget_show(item); + + /* This is also an easter egg, see the previous comment. */ + item = gtk_menu_item_new_with_label(_("If you look real closely")); + gtk_menu_shell_prepend(GTK_MENU_SHELL(widget), item); + gtk_widget_show(item); +} + +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +static void +pidgin_proxy_options_get_property(GObject *obj, guint param_id, GValue *value, + GParamSpec *pspec) +{ + PidginProxyOptions *options = PIDGIN_PROXY_OPTIONS(obj); + + switch(param_id) { + case PROP_SHOW_GLOBAL: + g_value_set_boolean(value, + pidgin_proxy_options_get_show_global(options)); + break; + case PROP_INFO: + g_value_set_object(value, pidgin_proxy_options_get_info(options)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); + break; + } +} + +static void +pidgin_proxy_options_set_property(GObject *obj, guint param_id, + const GValue *value, GParamSpec *pspec) +{ + PidginProxyOptions *options = PIDGIN_PROXY_OPTIONS(obj); + + switch(param_id) { + case PROP_SHOW_GLOBAL: + pidgin_proxy_options_set_show_global(options, + g_value_get_boolean(value)); + break; + case PROP_INFO: + pidgin_proxy_options_set_info(options, g_value_get_object(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); + break; + } +} + +static void +pidgin_proxy_options_init(PidginProxyOptions *options) { + gtk_widget_init_template(GTK_WIDGET(options)); + + /* Set the visible function so we can control the visibility of the "Use + * Global Proxy" option. + */ + gtk_tree_model_filter_set_visible_func(options->filter, + pidgin_proxy_options_filter_visible, + options, NULL); +} + +static void +pidgin_proxy_options_constructed(GObject *obj) { + PidginProxyOptions *options = PIDGIN_PROXY_OPTIONS(obj); + + G_OBJECT_CLASS(pidgin_proxy_options_parent_class)->constructed(obj); + + if(options->info == NULL) { + pidgin_proxy_options_set_info(options, NULL); + } +} + +static void +pidgin_proxy_options_class_init(PidginProxyOptionsClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + + obj_class->get_property = pidgin_proxy_options_get_property; + obj_class->set_property = pidgin_proxy_options_set_property; + obj_class->constructed = pidgin_proxy_options_constructed; + + /** + * PidginProxyOptions::show-global: + * + * Whether or not to show the "Use Global Proxy Settings" option. This + * is turned off for the preferences where we use this widget to define + * the global proxy settings. + * + * Since: 3.0.0 + */ + properties[PROP_SHOW_GLOBAL] = g_param_spec_boolean( + "show-global", "show-global", + "Whether or not to show the global proxy settings option", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + + /** + * PidginProxyOptions::info: + * + * The [class@Purple.ProxyInfo] that this options widget is configuring. If + * unset, a new instance will be created. + * + * Since: 3.0.0 + */ + properties[PROP_INFO] = g_param_spec_object( + "info", "info", + "The proxy info to configure", + PURPLE_TYPE_PROXY_INFO, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(obj_class, N_PROPERTIES, properties); + + gtk_widget_class_set_template_from_resource( + widget_class, + "/im/pidgin/Pidgin3/proxyoptions.ui" + ); + + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + model); + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + filter); + + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + proxy_type); + + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + options); + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + hostname); + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + port); + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + username); + gtk_widget_class_bind_template_child(widget_class, PidginProxyOptions, + password); + + gtk_widget_class_bind_template_callback(widget_class, + pidgin_proxy_options_proxy_type_changed_cb); + gtk_widget_class_bind_template_callback(widget_class, + pidgin_proxy_options_ports_popup_cb); +} + +/****************************************************************************** + * Public API + *****************************************************************************/ +GtkWidget * +pidgin_proxy_options_new(void) { + return g_object_new(PIDGIN_TYPE_PROXY_OPTIONS, NULL); +} + +void +pidgin_proxy_options_set_show_global(PidginProxyOptions *options, + gboolean show_global) +{ + PurpleProxyType proxy_type = PURPLE_PROXY_TYPE_USE_GLOBAL; + + g_return_if_fail(PIDGIN_IS_PROXY_OPTIONS(options)); + + if(show_global == options->show_global) { + return; + } + + options->show_global = show_global; + + if(options->info == NULL) { + g_object_notify_by_pspec(G_OBJECT(options), + properties[PROP_SHOW_GLOBAL]); + + return; + } + + proxy_type = purple_proxy_info_get_proxy_type(options->info); + if(proxy_type == PURPLE_PROXY_TYPE_USE_GLOBAL && show_global == FALSE) { + proxy_type = PURPLE_PROXY_TYPE_NONE; + } + + purple_proxy_info_set_proxy_type(options->info, proxy_type); + + options->show_global = show_global; + + g_object_notify_by_pspec(G_OBJECT(options), properties[PROP_SHOW_GLOBAL]); + + /* Tell the filter to rerun. */ + gtk_tree_model_filter_refilter(options->filter); +} + +gboolean +pidgin_proxy_options_get_show_global(PidginProxyOptions *options) { + g_return_val_if_fail(PIDGIN_IS_PROXY_OPTIONS(options), FALSE); + + return options->show_global; +} + +void +pidgin_proxy_options_set_info(PidginProxyOptions *options, + PurpleProxyInfo *info) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + g_return_if_fail(PIDGIN_IS_PROXY_OPTIONS(options)); + + /* We want to always have a PurpleProxyInfo instance to make management + * easier. So if someone clears it, just replace it with an empty one + * instead. + */ + if(!PURPLE_IS_PROXY_INFO(info)) { + PurpleProxyInfo *empty_info = purple_proxy_info_new(); + + if(!g_set_object(&options->info, empty_info)) { + g_assert_not_reached(); + } + + g_object_unref(empty_info); + } else if(!g_set_object(&options->info, info)) { + return; + } + + model = GTK_TREE_MODEL(options->filter); + if(gtk_tree_model_get_iter_first(model, &iter)) { + do { + PurpleProxyType type = purple_proxy_info_get_proxy_type(options->info); + PurpleProxyType row_type; + + gtk_tree_model_get(model, &iter, COLUMN_TYPE, &row_type, -1); + if(row_type == type) { + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(options->proxy_type), + &iter); + break; + } + } while(gtk_tree_model_iter_next(model, &iter)); + } + + g_object_bind_property_full(options->info, "hostname", + options->hostname, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + pidgin_proxy_options_null_to_empty_str, + pidgin_proxy_options_empty_str_to_null, + NULL, + NULL); + + g_object_bind_property_full(options->info, "port", + options->port, "value", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + pidgin_proxy_options_gint_to_double, + pidgin_proxy_options_double_to_gint, + NULL, + NULL); + + g_object_bind_property_full(options->info, "username", + options->username, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + pidgin_proxy_options_null_to_empty_str, + pidgin_proxy_options_empty_str_to_null, + NULL, + NULL); + + + g_object_bind_property_full(options->info, "password", + options->password, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + pidgin_proxy_options_null_to_empty_str, + pidgin_proxy_options_empty_str_to_null, + NULL, + NULL); + + g_object_notify_by_pspec(G_OBJECT(options), properties[PROP_INFO]); +} + +PurpleProxyInfo * +pidgin_proxy_options_get_info(PidginProxyOptions *options) { + g_return_val_if_fail(PIDGIN_IS_PROXY_OPTIONS(options), NULL); + + return options->info; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pidginproxyoptions.h Mon May 02 23:43:16 2022 -0500 @@ -0,0 +1,108 @@ +/* + * Pidgin - Internet Messenger + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * + * Pidgin is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION) +# error "only <pidgin.h> may be included directly" +#endif + +#ifndef PIDGIN_PROXY_OPTIONS_H +#define PIDGIN_PROXY_OPTIONS_H + +#include <gtk/gtk.h> + +#include <purple.h> + +G_BEGIN_DECLS + +/** + * PidginProxyOptions: + * + * A widget for the proxy options in the account editor. + * + * Since: 3.0.0 + */ + +#define PIDGIN_TYPE_PROXY_OPTIONS (pidgin_proxy_options_get_type()) +G_DECLARE_FINAL_TYPE(PidginProxyOptions, pidgin_proxy_options, PIDGIN, + PROXY_OPTIONS, GtkBox) + +/** + * pidgin_proxy_options_new: + * + * Creates a new proxy options widget. + * + * Returns: (transfer full): The widget. + * + * Since: 3.0.0 + */ +GtkWidget *pidgin_proxy_options_new(void); + +/** + * pidgin_proxy_options_set_show_global: + * @options: The instance. + * @show_global: Whether or not to show the use global settings proxy item. + * + * Sets whether or not to show the "Use Global Proxy Settings" item. + * + * Since: 3.0.0 + */ +void pidgin_proxy_options_set_show_global(PidginProxyOptions *options, gboolean show_global); + +/** + * pidgin_proxy_options_get_show_global: + * @options: The instance. + * + * Gets whether or not @options is displaying the "Use Global Proxy Settings" + * item. + * + * Returns: %TRUE if displaying it, %FALSE otherwise. + * + * Since: 3.0.0 + */ +gboolean pidgin_proxy_options_get_show_global(PidginProxyOptions *options); + +/** + * pidgin_proxy_options_get_info: + * @options: The instance. + * + * Gets the [class@Purple.ProxyInfo] that is being configured. + * + * Returns: (transfer none): The proxy info. + * + * Since: 3.0.0 + */ +PurpleProxyInfo *pidgin_proxy_options_get_info(PidginProxyOptions *options); + +/** + * pidgin_proxy_options_set_info: + * @options: The instance. + * @info: The [class@Purple.ProxyInfo] to set. + * + * The proxy info that will be configured. + * + * Since: 3.0.0 + */ +void pidgin_proxy_options_set_info(PidginProxyOptions *options, PurpleProxyInfo *info); + +G_END_DECLS + +#endif /* PIDGIN_PROXY_OPTIONS_H */
--- a/pidgin/resources/pidgin.gresource.xml Mon May 02 21:57:35 2022 -0500 +++ b/pidgin/resources/pidgin.gresource.xml Mon May 02 23:43:16 2022 -0500 @@ -37,6 +37,7 @@ <file compressed="true">Xfer/xfer.ui</file> <file compressed="true">closebutton.ui</file> <file compressed="true">gtk/menus.ui</file> + <file compressed="true">proxyoptions.ui</file> <file compressed="true">statusprimitivechooser.ui</file> <file>icons/16x16/status/pidgin-user-available.png</file> <file>icons/16x16/status/pidgin-user-away.png</file>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/resources/proxyoptions.ui Mon May 02 23:43:16 2022 -0500 @@ -0,0 +1,305 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 + +Pidgin - Internet Messenger +Copyright (C) Pidgin Developers <devel@pidgin.im> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +--> +<interface> + <requires lib="gtk+" version="3.24"/> + <!-- interface-license-type gplv2 --> + <!-- interface-name Pidgin --> + <!-- interface-description Internet Messenger --> + <!-- interface-copyright Pidgin Developers <devel@pidgin.im> --> + <object class="GtkListStore" id="model"> + <columns> + <!-- column-name type --> + <column type="PurpleProxyType"/> + <!-- column-name description --> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0">PURPLE_PROXY_TYPE_USE_GLOBAL</col> + <col id="1" translatable="yes">Use Global Proxy Settings</col> + </row> + <row> + <col id="0">PURPLE_PROXY_TYPE_NONE</col> + <col id="1" translatable="yes">No Proxy</col> + </row> + <row> + <col id="0">PURPLE_PROXY_TYPE_SOCKS4</col> + <col id="1" translatable="yes">SOCKS 4</col> + </row> + <row> + <col id="0">PURPLE_PROXY_TYPE_SOCKS5</col> + <col id="1" translatable="yes">SOCKS 5</col> + </row> + <row> + <col id="0">PURPLE_PROXY_TYPE_TOR</col> + <col id="1" translatable="yes">TOR/Privacy (SOCKS 5)</col> + </row> + <row> + <col id="0">PURPLE_PROXY_TYPE_HTTP</col> + <col id="1" translatable="yes">HTTP</col> + </row> + <row> + <col id="0">PURPLE_PROXY_TYPE_USE_ENVVAR</col> + <col id="1" translatable="yes">Use Environmental Settings</col> + </row> + </data> + </object> + <object class="GtkTreeModelFilter" id="filter"> + <property name="child-model">model</property> + </object> + <object class="GtkAdjustment" id="port_adjustment"> + <property name="lower">-1</property> + <property name="upper">65535</property> + <property name="step-increment">1</property> + <property name="page-increment">10</property> + </object> + <template class="PidginProxyOptions" parent="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkLabel" id="proxy_type_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">Proxy _type:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">proxy_type</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="proxy_type"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="model">filter</property> + <signal name="changed" handler="pidgin_proxy_options_proxy_type_changed_cb" object="PidginProxyOptions" swapped="no"/> + <child> + <object class="GtkCellRendererText"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="options"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkLabel" id="host_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">_Host:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">hostname</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="hostname"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="progress-pulse-step">0</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkLabel" id="port_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">_Port:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">port</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="port"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="input-hints">GTK_INPUT_HINT_NO_EMOJI | GTK_INPUT_HINT_NONE</property> + <property name="adjustment">port_adjustment</property> + <property name="numeric">True</property> + <signal name="populate-popup" handler="pidgin_proxy_options_ports_popup_cb" object="PidginProxyOptions" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkLabel" id="username_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">_Username:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">username</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="username"> + <property name="visible">True</property> + <property name="can-focus">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkLabel" id="password_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">Pa_ssword:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">password</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="password"> + <property name="visible">True</property> + <property name="can-focus">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </template> + <object class="GtkSizeGroup"> + <widgets> + <widget name="proxy_type_label"/> + <widget name="host_label"/> + <widget name="port_label"/> + <widget name="username_label"/> + <widget name="password_label"/> + </widgets> + </object> +</interface>
--- a/po/POTFILES.in Mon May 02 21:57:35 2022 -0500 +++ b/po/POTFILES.in Mon May 02 23:43:16 2022 -0500 @@ -336,6 +336,7 @@ pidgin/pidginaccountchooser.c pidgin/pidginaccountfilterconnected.c pidgin/pidginaccountfilterprotocol.c +pidgin/pidginaccountmanager.c pidgin/pidginaccountsenabledmenu.c pidgin/pidginaccountsmenu.c pidgin/pidginaccountstore.c @@ -364,6 +365,7 @@ pidgin/pidginpresenceicon.c pidgin/pidginprotocolchooser.c pidgin/pidginprotocolstore.c +pidgin/pidginproxyoptions.c pidgin/pidginscrollbook.c pidgin/pidginstatusbox.c pidgin/pidginstatusprimitivechooser.c @@ -415,6 +417,7 @@ pidgin/resources/Whiteboard/whiteboard.ui pidgin/resources/Xfer/xfer.ui pidgin/resources/gtk/menus.ui +pidgin/resources/proxyoptions.ui pidgin/win32/gtkwin32dep.c pidgin/win32/winpidgin.c purple-history/purplehistorycore.c