// SPDX-License-Identifier: GPL-2.0+ /* NetworkManager Connection editor -- Connection editor for NetworkManager * * Dan Williams * * Copyright 2009 - 2017 Red Hat, Inc. */ #include "nm-default.h" #include #include "ce-polkit-button.h" G_DEFINE_TYPE (CEPolkitButton, ce_polkit_button, GTK_TYPE_BUTTON) #define CE_POLKIT_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_POLKIT_BUTTON, CEPolkitButtonPrivate)) typedef struct { char *tooltip; char *auth_tooltip; char *validation_error; GtkWidget *icon; GtkWidget *auth; NMClient *client; NMClientPermission permission; NMClientPermissionResult permission_result; guint perm_id; } CEPolkitButtonPrivate; enum { ACTIONABLE, AUTHORIZED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void update_button (CEPolkitButton *self) { CEPolkitButtonPrivate *priv = CE_POLKIT_BUTTON_GET_PRIVATE (self); gboolean actionable; actionable = ce_polkit_button_get_actionable (self); gtk_widget_set_sensitive (GTK_WIDGET (self), actionable); if (priv->validation_error) gtk_widget_set_tooltip_text (GTK_WIDGET (self), priv->validation_error); else if (priv->permission_result == NM_CLIENT_PERMISSION_RESULT_AUTH) gtk_widget_set_tooltip_text (GTK_WIDGET (self), priv->auth_tooltip); else if (priv->permission_result == NM_CLIENT_PERMISSION_RESULT_YES) gtk_widget_set_tooltip_text (GTK_WIDGET (self), priv->tooltip); else gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("No polkit authorization to perform the action")); if (priv->permission_result == NM_CLIENT_PERMISSION_RESULT_YES) gtk_button_set_image (GTK_BUTTON (self), priv->icon); else gtk_button_set_image (GTK_BUTTON (self), priv->auth); } static void update_and_emit (CEPolkitButton *self, gboolean old_actionable) { gboolean new_actionable; new_actionable = ce_polkit_button_get_actionable (self); update_button (self); if (new_actionable != old_actionable) g_signal_emit (self, signals[ACTIONABLE], 0, new_actionable); } void ce_polkit_button_set_validation_error (CEPolkitButton *self, const char *validation_error) { CEPolkitButtonPrivate *priv; gboolean old_actionable; g_return_if_fail (self != NULL); g_return_if_fail (CE_IS_POLKIT_BUTTON (self)); priv = CE_POLKIT_BUTTON_GET_PRIVATE (self); if (g_strcmp0 (validation_error, priv->validation_error) != 0) { old_actionable = ce_polkit_button_get_actionable (self); g_free (priv->validation_error); priv->validation_error = g_strdup (validation_error); update_and_emit (self, old_actionable); } } gboolean ce_polkit_button_get_actionable (CEPolkitButton *self) { CEPolkitButtonPrivate *priv; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (CE_IS_POLKIT_BUTTON (self), FALSE); priv = CE_POLKIT_BUTTON_GET_PRIVATE (self); return !priv->validation_error && ce_polkit_button_get_authorized (self); } gboolean ce_polkit_button_get_authorized (CEPolkitButton *self) { CEPolkitButtonPrivate *priv; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (CE_IS_POLKIT_BUTTON (self), FALSE); priv = CE_POLKIT_BUTTON_GET_PRIVATE (self); return priv->permission_result == NM_CLIENT_PERMISSION_RESULT_YES || priv->permission_result == NM_CLIENT_PERMISSION_RESULT_AUTH; } static void permission_changed_cb (NMClient *client, NMClientPermission permission, NMClientPermissionResult result, CEPolkitButton *self) { CEPolkitButtonPrivate *priv = CE_POLKIT_BUTTON_GET_PRIVATE (self); gboolean old_actionable; if (priv->permission_result == result) return; old_actionable = ce_polkit_button_get_actionable (self); priv->permission_result = result; update_and_emit (self, old_actionable); g_signal_emit (self, signals[AUTHORIZED], 0, ce_polkit_button_get_authorized (self)); } GtkWidget * ce_polkit_button_new (const char *label, const char *tooltip, const char *auth_tooltip, const char *icon_name, NMClient *client, NMClientPermission permission) { GObject *object; CEPolkitButtonPrivate *priv; object = g_object_new (CE_TYPE_POLKIT_BUTTON, NULL); if (!object) return NULL; priv = CE_POLKIT_BUTTON_GET_PRIVATE (object); priv->tooltip = g_strdup (tooltip); priv->auth_tooltip = g_strdup (auth_tooltip); priv->permission = permission; priv->client = g_object_ref (client); priv->perm_id = g_signal_connect (client, "permission-changed", G_CALLBACK (permission_changed_cb), object); priv->icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON); g_object_ref_sink (priv->icon); priv->auth = gtk_image_new_from_icon_name ("dialog-password", GTK_ICON_SIZE_BUTTON); g_object_ref_sink (priv->auth); gtk_button_set_label (GTK_BUTTON (object), label); update_button (CE_POLKIT_BUTTON (object)); permission_changed_cb (client, permission, nm_client_get_permission_result (client, permission), CE_POLKIT_BUTTON (object)); return GTK_WIDGET (object); } static void dispose (GObject *object) { CEPolkitButtonPrivate *priv = CE_POLKIT_BUTTON_GET_PRIVATE (object); if (priv->perm_id) { g_signal_handler_disconnect (priv->client, priv->perm_id); priv->perm_id = 0; } g_clear_object (&priv->client); g_clear_object (&priv->auth); g_clear_object (&priv->icon); G_OBJECT_CLASS (ce_polkit_button_parent_class)->dispose (object); } static void finalize (GObject *object) { CEPolkitButtonPrivate *priv = CE_POLKIT_BUTTON_GET_PRIVATE (object); g_free (priv->tooltip); g_free (priv->auth_tooltip); g_free (priv->validation_error); G_OBJECT_CLASS (ce_polkit_button_parent_class)->finalize (object); } static void ce_polkit_button_init (CEPolkitButton *self) { } static void ce_polkit_button_class_init (CEPolkitButtonClass *pb_class) { GObjectClass *object_class = G_OBJECT_CLASS (pb_class); g_type_class_add_private (object_class, sizeof (CEPolkitButtonPrivate)); object_class->dispose = dispose; object_class->finalize = finalize; signals[ACTIONABLE] = g_signal_new ("actionable", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CEPolkitButtonClass, actionable), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); signals[AUTHORIZED] = g_signal_new ("authorized", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CEPolkitButtonClass, authorized), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); }