Fri, 16 Sep 2022 01:54:11 -0500
Change the credential provider row active indicator to a CheckButton
Because I noticed that Adw has a style that is for this sort of thing.
Testing Done:
Opened Credential prefs, and changed selected provider. Also checked that clicking the check button didn't accidentally change its state without changing the row, and that it could not be selected by keyboard separately from the row.
Reviewed at https://reviews.imfreedom.org/r/1775/
/* * 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; }