pidgin/pidginproxyoptions.c

Fri, 26 Aug 2022 03:51:08 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 26 Aug 2022 03:51:08 -0500
branch
gtk4
changeset 41605
2e2adf4729e7
parent 41543
d6ba57accc0e
permissions
-rw-r--r--

Fix the Windows build against GTK4

Fix the Windows against GTK4

Testing Done:
Compiled and ran on Windows.

Reviewed at https://reviews.imfreedom.org/r/1660/

/*
 * 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);
}

/******************************************************************************
 * 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);

	/* Force the filter to refresh. */
	gtk_tree_model_filter_refilter(options->filter);
}

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);
}

/******************************************************************************
 * 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;
}

mercurial