pidgin/pidgin

Create a PidginProxyOptions widget

2022-05-02, Gary Kramlich
2bdf14aaf7a1
Parents 15aeaa1e84ec
Children a2cd8d6d9483
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