summaryrefslogtreecommitdiffstats
path: root/panels/wwan/cc-wwan-device-page.c
diff options
context:
space:
mode:
Diffstat (limited to 'panels/wwan/cc-wwan-device-page.c')
-rw-r--r--panels/wwan/cc-wwan-device-page.c650
1 files changed, 650 insertions, 0 deletions
diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c
new file mode 100644
index 0000000..13aa87a
--- /dev/null
+++ b/panels/wwan/cc-wwan-device-page.c
@@ -0,0 +1,650 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* cc-wwan-device-page.c
+ *
+ * Copyright 2019 Purism SPC
+ *
+ * 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 3 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author(s):
+ * Mohammed Sadiq <sadiq@sadiqpk.org>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "cc-wwan-device-page"
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <libmm-glib.h>
+#define GCR_API_SUBJECT_TO_CHANGE
+#include <gcr/gcr-base.h>
+
+#include "cc-list-row.h"
+#include "cc-wwan-data.h"
+#include "cc-wwan-mode-dialog.h"
+#include "cc-wwan-network-dialog.h"
+#include "cc-wwan-details-dialog.h"
+#include "cc-wwan-sim-lock-dialog.h"
+#include "cc-wwan-apn-dialog.h"
+#include "cc-wwan-device-page.h"
+#include "cc-wwan-resources.h"
+
+#include "shell/cc-application.h"
+#include "shell/cc-debug.h"
+#include "shell/cc-object-storage.h"
+
+/**
+ * @short_description: Device settings page
+ * @include: "cc-wwan-device-page.h"
+ *
+ * The Device page allows users to configure device
+ * settings. Please note that there is no one-to-one
+ * maping for a device settings page and a physical
+ * device. Say, if a device have two SIM card slots,
+ * there should be two device pages, one for each SIM.
+ */
+
+struct _CcWwanDevicePage
+{
+ GtkBox parent_instance;
+
+ GtkListBox *advanced_settings_list;
+ CcListRow *apn_settings_row;
+ CcListRow *data_enable_row;
+ CcListRow *data_roaming_row;
+ GtkListBox *data_settings_list;
+ CcListRow *details_row;
+ GtkStack *main_stack;
+ CcListRow *network_mode_row;
+ CcListRow *network_name_row;
+ GtkListBox *network_settings_list;
+ CcListRow *sim_lock_row;
+ GtkButton *unlock_button;
+
+ AdwToastOverlay *toast_overlay;
+
+ CcWwanDevice *device;
+ CcWwanData *wwan_data;
+ GDBusProxy *wwan_proxy;
+
+ CcWwanApnDialog *apn_dialog;
+ CcWwanDetailsDialog *details_dialog;
+ CcWwanModeDialog *network_mode_dialog;
+ CcWwanNetworkDialog *network_dialog;
+ CcWwanSimLockDialog *sim_lock_dialog;
+
+ gint sim_index;
+ /* Set if a change is triggered in a signal’s callback,
+ * to avoid re-triggering of callback. This is used
+ * instead of blocking handlers where the signal may be
+ * emitted async and the block/unblock may not work right
+ */
+ gboolean is_self_change;
+ gboolean is_retry;
+};
+
+G_DEFINE_TYPE (CcWwanDevicePage, cc_wwan_device_page, GTK_TYPE_BOX)
+
+enum {
+ PROP_0,
+ PROP_DEVICE,
+ N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS];
+
+static void
+wwan_device_page_handle_data_row (CcWwanDevicePage *self,
+ CcListRow *data_row)
+{
+ gboolean active;
+
+ /* The user dismissed the dialog for selecting default APN */
+ if (cc_wwan_data_get_default_apn (self->wwan_data) == NULL)
+ {
+ self->is_self_change = TRUE;
+ gtk_widget_activate (GTK_WIDGET (data_row));
+
+ return;
+ }
+
+ active = cc_list_row_get_active (data_row);
+
+ if (data_row == self->data_enable_row)
+ cc_wwan_data_set_enabled (self->wwan_data, active);
+ else
+ cc_wwan_data_set_roaming_enabled (self->wwan_data, active);
+
+ cc_wwan_data_save_settings (self->wwan_data, NULL, NULL, NULL);
+}
+
+static gboolean
+wwan_apn_dialog_closed_cb (CcWwanDevicePage *self)
+{
+ CcListRow *data_row;
+
+ if (gtk_widget_in_destruction (GTK_WIDGET (self)))
+ return FALSE;
+
+ data_row = g_object_get_data (G_OBJECT (self->apn_dialog), "row");
+ g_object_set_data (G_OBJECT (self->apn_dialog), "row", NULL);
+
+ if (data_row)
+ wwan_device_page_handle_data_row (self, data_row);
+
+ return FALSE;
+}
+
+static void
+wwan_data_show_apn_dialog (CcWwanDevicePage *self)
+{
+ GtkWindow *top_level;
+
+ top_level = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
+
+ if (!self->apn_dialog)
+ {
+ self->apn_dialog = cc_wwan_apn_dialog_new (top_level, self->device);
+ g_signal_connect_object (self->apn_dialog, "unmap",
+ G_CALLBACK (wwan_apn_dialog_closed_cb),
+ self, G_CONNECT_SWAPPED);
+ }
+
+ gtk_widget_show (GTK_WIDGET (self->apn_dialog));
+}
+
+static GcrPrompt *
+cc_wwan_device_page_new_prompt (CcWwanDevicePage *self,
+ MMModemLock lock)
+{
+ GcrPrompt *prompt;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *description = NULL;
+ g_autofree gchar *warning = NULL;
+ const gchar *message = NULL;
+ guint num;
+
+ prompt = GCR_PROMPT (gcr_system_prompt_open (-1, NULL, &error));
+
+ if (error)
+ {
+ g_warning ("Error opening Prompt: %s", error->message);
+ return NULL;
+ }
+
+ gcr_prompt_set_title (prompt, _("Unlock SIM card"));
+ gcr_prompt_set_continue_label (prompt, _("Unlock"));
+ gcr_prompt_set_cancel_label (prompt, _("Cancel"));
+
+ if (lock == MM_MODEM_LOCK_SIM_PIN)
+ {
+ description = g_strdup_printf (_("Please provide PIN code for SIM %d"), self->sim_index);
+ message = _("Enter PIN to unlock your SIM card");
+ }
+ else if (lock == MM_MODEM_LOCK_SIM_PUK)
+ {
+ description = g_strdup_printf (_("Please provide PUK code for SIM %d"), self->sim_index);
+ message = _("Enter PUK to unlock your SIM card");
+ }
+ else
+ {
+ g_warn_if_reached ();
+ g_object_unref (prompt);
+
+ return NULL;
+ }
+
+ gcr_prompt_set_description (prompt, description);
+ gcr_prompt_set_message (prompt, message);
+
+ num = cc_wwan_device_get_unlock_retries (self->device, lock);
+
+ if (num != MM_UNLOCK_RETRIES_UNKNOWN)
+ {
+ if (self->is_retry)
+ warning = g_strdup_printf (ngettext ("Wrong password entered. You have %1$u try left",
+ "Wrong password entered. You have %1$u tries left", num), num);
+ else
+ warning = g_strdup_printf (ngettext ("You have %u try left",
+ "You have %u tries left", num), num);
+ }
+ else if (self->is_retry)
+ {
+ warning = g_strdup (_("Wrong password entered."));
+ }
+
+ gcr_prompt_set_warning (prompt, warning);
+
+ return prompt;
+}
+
+static void
+wwan_update_unlock_button (CcWwanDevicePage *self)
+{
+ gtk_button_set_label (self->unlock_button, _("Unlock"));
+ gtk_widget_set_sensitive (GTK_WIDGET (self->unlock_button), TRUE);
+}
+
+static void
+cc_wwan_device_page_unlocked_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CcWwanDevicePage *self = user_data;
+ wwan_update_unlock_button (self);
+}
+
+static void
+wwan_device_unlock_clicked_cb (CcWwanDevicePage *self)
+{
+ g_autoptr(GError) error = NULL;
+ GcrPrompt *prompt;
+ const gchar *password, *warning;
+ const gchar *pin = "";
+ const gchar *puk = "";
+ MMModemLock lock;
+
+ lock = cc_wwan_device_get_lock (self->device);
+ password = "";
+
+ if (lock != MM_MODEM_LOCK_SIM_PIN &&
+ lock != MM_MODEM_LOCK_SIM_PUK)
+ g_return_if_reached ();
+
+ if (lock == MM_MODEM_LOCK_SIM_PUK)
+ {
+ prompt = cc_wwan_device_page_new_prompt (self, lock);
+
+ warning = _("PUK code should be an 8 digit number");
+ while (password && !cc_wwan_device_pin_valid (password, lock))
+ {
+ password = gcr_prompt_password (prompt, NULL, &error);
+ gcr_prompt_set_warning (prompt, warning);
+ }
+
+ puk = g_strdup (password);
+ password = "";
+ gcr_prompt_close (prompt);
+ g_object_unref (prompt);
+
+ if (error)
+ g_warning ("Error: %s", error->message);
+
+ /* Error or User cancelled PUK */
+ if (!puk)
+ return;
+ }
+
+ prompt = cc_wwan_device_page_new_prompt (self, MM_MODEM_LOCK_SIM_PIN);
+ if (lock == MM_MODEM_LOCK_SIM_PUK)
+ {
+ gcr_prompt_set_password_new (prompt, TRUE);
+ gcr_prompt_set_message (prompt, _("Enter New PIN"));
+ gcr_prompt_set_warning (prompt, "");
+ }
+
+ warning = _("PIN code should be a 4-8 digit number");
+ while (password && !cc_wwan_device_pin_valid (password, MM_MODEM_LOCK_SIM_PIN))
+ {
+ password = gcr_prompt_password (prompt, NULL, &error);
+ gcr_prompt_set_warning (prompt, warning);
+ }
+
+ pin = g_strdup (password);
+ gcr_prompt_close (prompt);
+ g_object_unref (prompt);
+
+ if (error)
+ g_warning ("Error: %s", error->message);
+
+ /* Error or User cancelled PIN */
+ if (!pin)
+ return;
+
+ gtk_button_set_label (self->unlock_button, _("Unlocking…"));
+ gtk_widget_set_sensitive (GTK_WIDGET (self->unlock_button), FALSE);
+
+ if (lock == MM_MODEM_LOCK_SIM_PIN)
+ cc_wwan_device_send_pin (self->device, pin,
+ NULL, /* cancellable */
+ cc_wwan_device_page_unlocked_cb,
+ self);
+ else if (lock == MM_MODEM_LOCK_SIM_PUK)
+ {
+ cc_wwan_device_send_puk (self->device, puk, pin,
+ NULL, /* Cancellable */
+ cc_wwan_device_page_unlocked_cb,
+ self);
+ }
+ else
+ {
+ g_warn_if_reached ();
+ }
+}
+
+static void
+wwan_data_settings_changed_cb (CcWwanDevicePage *self,
+ GParamSpec *pspec,
+ CcListRow *data_row)
+{
+ if (self->is_self_change)
+ {
+ self->is_self_change = FALSE;
+ return;
+ }
+
+ if (cc_wwan_data_get_default_apn (self->wwan_data) == NULL)
+ {
+ wwan_data_show_apn_dialog (self);
+ g_object_set_data (G_OBJECT (self->apn_dialog), "row", data_row);
+ }
+ else
+ {
+ wwan_device_page_handle_data_row (self, data_row);
+ }
+}
+
+static void
+wwan_network_settings_activated_cb (CcWwanDevicePage *self,
+ CcListRow *row)
+{
+ GtkWidget *dialog;
+ GtkWindow *top_level;
+
+ top_level = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
+
+ if (row == self->network_mode_row)
+ {
+ if (!self->network_mode_dialog)
+ self->network_mode_dialog = cc_wwan_mode_dialog_new (top_level, self->device);
+
+ dialog = GTK_WIDGET (self->network_mode_dialog);
+ }
+ else if (row == self->network_name_row)
+ {
+ if (!self->network_dialog)
+ self->network_dialog = cc_wwan_network_dialog_new (top_level, self->device);
+
+ dialog = GTK_WIDGET (self->network_dialog);
+ }
+ else
+ {
+ return;
+ }
+
+ gtk_widget_show (dialog);
+}
+
+static void
+wwan_advanced_settings_activated_cb (CcWwanDevicePage *self,
+ CcListRow *row)
+{
+ GtkWindow *top_level;
+
+ top_level = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
+
+ if (row == self->sim_lock_row)
+ {
+ if (!self->sim_lock_dialog)
+ self->sim_lock_dialog = cc_wwan_sim_lock_dialog_new (top_level, self->device);
+ gtk_widget_show (GTK_WIDGET (self->sim_lock_dialog));
+ }
+ else if (row == self->details_row)
+ {
+ if (!self->details_dialog)
+ self->details_dialog = cc_wwan_details_dialog_new (top_level, self->device);
+ gtk_widget_show (GTK_WIDGET (self->details_dialog));
+ }
+ else if (row == self->apn_settings_row)
+ {
+ wwan_data_show_apn_dialog (self);
+ }
+ else
+ {
+ g_return_if_reached ();
+ }
+}
+
+static void
+cc_wwan_device_page_update_data (CcWwanDevicePage *self)
+{
+ gboolean has_data;
+
+ if (self->wwan_data == cc_wwan_device_get_data (self->device))
+ return;
+
+ self->wwan_data = cc_wwan_device_get_data (self->device);
+ has_data = self->wwan_data != NULL;
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self->data_settings_list), has_data);
+ gtk_widget_set_sensitive (GTK_WIDGET (self->apn_settings_row), has_data);
+
+ if (!has_data)
+ return;
+
+ g_signal_handlers_block_by_func (self->data_roaming_row,
+ wwan_data_settings_changed_cb, self);
+ g_signal_handlers_block_by_func (self->data_enable_row,
+ wwan_data_settings_changed_cb, self);
+
+ g_object_set (self->data_roaming_row, "active",
+ cc_wwan_data_get_roaming_enabled (self->wwan_data), NULL);
+
+ g_object_set (self->data_enable_row, "active",
+ cc_wwan_data_get_enabled (self->wwan_data), NULL);
+
+ g_signal_handlers_unblock_by_func (self->data_roaming_row,
+ wwan_data_settings_changed_cb, self);
+ g_signal_handlers_unblock_by_func (self->data_enable_row,
+ wwan_data_settings_changed_cb, self);
+}
+
+static void
+cc_wwan_device_page_update (CcWwanDevicePage *self)
+{
+ GtkStack *main_stack;
+ MMModemLock lock;
+
+ main_stack = self->main_stack;
+ if (!cc_wwan_device_has_sim (self->device))
+ gtk_stack_set_visible_child_name (main_stack, "no-sim-view");
+ else if ((lock = cc_wwan_device_get_lock (self->device)) == MM_MODEM_LOCK_SIM_PIN ||
+ lock == MM_MODEM_LOCK_SIM_PUK)
+ gtk_stack_set_visible_child_name (main_stack, "sim-lock-view");
+ else
+ gtk_stack_set_visible_child_name (main_stack, "settings-view");
+}
+
+static void
+cc_wwan_locks_changed_cb (CcWwanDevicePage *self)
+{
+ const gchar *label;
+
+ if (cc_wwan_device_get_sim_lock (self->device))
+ label = _("Enabled");
+ else
+ label = _("Disabled");
+
+ cc_list_row_set_secondary_label (self->sim_lock_row, label);
+ cc_wwan_device_page_update (self);
+}
+
+static void
+cc_wwan_device_page_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CcWwanDevicePage *self = (CcWwanDevicePage *)object;
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE:
+ self->device = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+cc_wwan_device_page_constructed (GObject *object)
+{
+ CcWwanDevicePage *self = (CcWwanDevicePage *)object;
+
+ G_OBJECT_CLASS (cc_wwan_device_page_parent_class)->constructed (object);
+
+ cc_wwan_device_page_update_data (self);
+
+ g_object_bind_property (self->device, "operator-name",
+ self->network_name_row, "secondary-label",
+ G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (self->device, "network-mode",
+ self->network_mode_row, "secondary-label",
+ G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+
+ g_signal_connect_object (self->device, "notify::enabled-locks",
+ (GCallback)cc_wwan_locks_changed_cb,
+ self, G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (self->device, "notify::has-data",
+ (GCallback)cc_wwan_device_page_update_data,
+ self, G_CONNECT_SWAPPED);
+
+ cc_wwan_device_page_update (self);
+ cc_wwan_locks_changed_cb (self);
+}
+
+static void
+cc_wwan_device_page_dispose (GObject *object)
+{
+ CcWwanDevicePage *self = (CcWwanDevicePage *)object;
+
+ g_clear_pointer ((GtkWindow **)&self->apn_dialog, gtk_window_destroy);
+ g_clear_pointer ((GtkWindow **)&self->details_dialog, gtk_window_destroy);
+ g_clear_pointer ((GtkWindow **)&self->network_mode_dialog, gtk_window_destroy);
+ g_clear_pointer ((GtkWindow **)&self->network_dialog, gtk_window_destroy);
+ g_clear_pointer ((GtkWindow **)&self->sim_lock_dialog, gtk_window_destroy);
+
+ g_clear_object (&self->wwan_proxy);
+ g_clear_object (&self->device);
+
+ G_OBJECT_CLASS (cc_wwan_device_page_parent_class)->dispose (object);
+}
+
+static void
+cc_wwan_device_page_class_init (CcWwanDevicePageClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = cc_wwan_device_page_set_property;
+ object_class->constructed = cc_wwan_device_page_constructed;
+ object_class->dispose = cc_wwan_device_page_dispose;
+
+ g_type_ensure (CC_TYPE_WWAN_DEVICE);
+
+ properties[PROP_DEVICE] =
+ g_param_spec_object ("device",
+ "Device",
+ "The WWAN Device",
+ CC_TYPE_WWAN_DEVICE,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/control-center/wwan/cc-wwan-device-page.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, advanced_settings_list);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, apn_settings_row);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, data_enable_row);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, data_roaming_row);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, data_settings_list);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, details_row);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, main_stack);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, network_mode_row);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, network_name_row);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, network_settings_list);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, sim_lock_row);
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, unlock_button);
+
+ gtk_widget_class_bind_template_callback (widget_class, wwan_device_unlock_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, wwan_data_settings_changed_cb);
+ gtk_widget_class_bind_template_callback (widget_class, wwan_network_settings_activated_cb);
+ gtk_widget_class_bind_template_callback (widget_class, wwan_advanced_settings_activated_cb);
+}
+
+static void
+cc_wwan_device_page_init (CcWwanDevicePage *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+cc_wwan_error_changed_cb (CcWwanDevicePage *self)
+{
+ AdwToast *toast;
+ const gchar *message;
+
+ message = cc_wwan_device_get_simple_error (self->device);
+
+ if (!message)
+ return;
+
+ toast = adw_toast_new (message);
+ adw_toast_overlay_add_toast (self->toast_overlay, toast);
+}
+
+CcWwanDevicePage *
+cc_wwan_device_page_new (CcWwanDevice *device,
+ GtkWidget *toast_overlay)
+{
+ CcWwanDevicePage *self;
+
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (device), NULL);
+
+ self = g_object_new (CC_TYPE_WWAN_DEVICE_PAGE,
+ "device", device,
+ NULL);
+
+ self->toast_overlay = ADW_TOAST_OVERLAY (toast_overlay);
+
+ g_signal_connect_object (self->device, "notify::error",
+ G_CALLBACK (cc_wwan_error_changed_cb),
+ self, G_CONNECT_SWAPPED);
+
+ return self;
+}
+
+CcWwanDevice *
+cc_wwan_device_page_get_device (CcWwanDevicePage *self)
+{
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE_PAGE (self), NULL);
+
+ return self->device;
+}
+
+void
+cc_wwan_device_page_set_sim_index (CcWwanDevicePage *self,
+ gint sim_index)
+{
+ g_return_if_fail (CC_IS_WWAN_DEVICE_PAGE (self));
+ g_return_if_fail (sim_index >= 1);
+
+ self->sim_index = sim_index;
+}