You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9200 lines
327 KiB
9200 lines
327 KiB
From aa65caa35ae1c69b8b6644c1a72eb8110500e7e0 Mon Sep 17 00:00:00 2001 |
|
From: Mohammed Sadiq <sadiq@sadiqpk.org> |
|
Date: Fri, 4 Oct 2019 12:27:26 +0530 |
|
Subject: [PATCH 1/7] common: Add polkit rules for modem management |
|
|
|
--- |
|
panels/common/gnome-control-center.rules.in | 1 + |
|
1 file changed, 1 insertion(+) |
|
|
|
diff --git a/panels/common/gnome-control-center.rules.in b/panels/common/gnome-control-center.rules.in |
|
index 971ffac63..22cf785e0 100644 |
|
--- a/panels/common/gnome-control-center.rules.in |
|
+++ b/panels/common/gnome-control-center.rules.in |
|
@@ -1,6 +1,7 @@ |
|
polkit.addRule(function(action, subject) { |
|
if ((action.id == "org.freedesktop.locale1.set-locale" || |
|
action.id == "org.freedesktop.locale1.set-keyboard" || |
|
+ action.id == "org.freedesktop.ModemManager1.Device.Control" || |
|
action.id == "org.freedesktop.hostname1.set-static-hostname" || |
|
action.id == "org.freedesktop.hostname1.set-hostname" || |
|
action.id == "org.gnome.controlcenter.datetime.configure") && |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 2b863f51831bc09d3ef56d16858724191ac9095c Mon Sep 17 00:00:00 2001 |
|
From: Mohammed Sadiq <sadiq@sadiqpk.org> |
|
Date: Fri, 4 Oct 2019 22:16:23 +0530 |
|
Subject: [PATCH 2/7] wwan: Add new panel for modem management |
|
|
|
The panel supports 2G/3G/4G GSM/LTE modems. CDMA2000 Modems are not supported. |
|
If a supported modem is present, the panel will be shown and the modem will be |
|
handled, else, network-panel shall manage the modem as it did in the past. |
|
|
|
If more than one modem with data enabled is present, the user is allowed to set |
|
priority of one SIM over the other (the priority is for SIM, not modem). |
|
|
|
Fixes https://gitlab.gnome.org/GNOME/gnome-control-center/issues/132 |
|
--- |
|
meson.build | 4 + |
|
panels/meson.build | 3 +- |
|
panels/wwan/cc-wwan-apn-dialog.c | 424 ++++++ |
|
panels/wwan/cc-wwan-apn-dialog.h | 40 + |
|
panels/wwan/cc-wwan-apn-dialog.ui | 249 ++++ |
|
panels/wwan/cc-wwan-data.c | 1446 ++++++++++++++++++++ |
|
panels/wwan/cc-wwan-data.h | 93 ++ |
|
panels/wwan/cc-wwan-details-dialog.c | 257 ++++ |
|
panels/wwan/cc-wwan-details-dialog.h | 40 + |
|
panels/wwan/cc-wwan-details-dialog.ui | 320 +++++ |
|
panels/wwan/cc-wwan-device-page.c | 634 +++++++++ |
|
panels/wwan/cc-wwan-device-page.h | 42 + |
|
panels/wwan/cc-wwan-device-page.ui | 270 ++++ |
|
panels/wwan/cc-wwan-device.c | 1355 ++++++++++++++++++ |
|
panels/wwan/cc-wwan-device.h | 152 ++ |
|
panels/wwan/cc-wwan-errors-private.h | 104 ++ |
|
panels/wwan/cc-wwan-mode-dialog.c | 327 +++++ |
|
panels/wwan/cc-wwan-mode-dialog.h | 40 + |
|
panels/wwan/cc-wwan-mode-dialog.ui | 57 + |
|
panels/wwan/cc-wwan-network-dialog.c | 443 ++++++ |
|
panels/wwan/cc-wwan-network-dialog.h | 40 + |
|
panels/wwan/cc-wwan-network-dialog.ui | 188 +++ |
|
panels/wwan/cc-wwan-panel.c | 929 +++++++++++++ |
|
panels/wwan/cc-wwan-panel.h | 36 + |
|
panels/wwan/cc-wwan-panel.ui | 336 +++++ |
|
panels/wwan/cc-wwan-sim-lock-dialog.c | 310 +++++ |
|
panels/wwan/cc-wwan-sim-lock-dialog.h | 40 + |
|
panels/wwan/cc-wwan-sim-lock-dialog.ui | 306 +++++ |
|
panels/wwan/gnome-wwan-panel.desktop.in.in | 16 + |
|
panels/wwan/meson.build | 61 + |
|
panels/wwan/wwan.gresource.xml | 12 + |
|
shell/cc-panel-list.c | 1 + |
|
shell/cc-panel-loader.c | 9 + |
|
33 files changed, 8583 insertions(+), 1 deletion(-) |
|
create mode 100644 panels/wwan/cc-wwan-apn-dialog.c |
|
create mode 100644 panels/wwan/cc-wwan-apn-dialog.h |
|
create mode 100644 panels/wwan/cc-wwan-apn-dialog.ui |
|
create mode 100644 panels/wwan/cc-wwan-data.c |
|
create mode 100644 panels/wwan/cc-wwan-data.h |
|
create mode 100644 panels/wwan/cc-wwan-details-dialog.c |
|
create mode 100644 panels/wwan/cc-wwan-details-dialog.h |
|
create mode 100644 panels/wwan/cc-wwan-details-dialog.ui |
|
create mode 100644 panels/wwan/cc-wwan-device-page.c |
|
create mode 100644 panels/wwan/cc-wwan-device-page.h |
|
create mode 100644 panels/wwan/cc-wwan-device-page.ui |
|
create mode 100644 panels/wwan/cc-wwan-device.c |
|
create mode 100644 panels/wwan/cc-wwan-device.h |
|
create mode 100644 panels/wwan/cc-wwan-errors-private.h |
|
create mode 100644 panels/wwan/cc-wwan-mode-dialog.c |
|
create mode 100644 panels/wwan/cc-wwan-mode-dialog.h |
|
create mode 100644 panels/wwan/cc-wwan-mode-dialog.ui |
|
create mode 100644 panels/wwan/cc-wwan-network-dialog.c |
|
create mode 100644 panels/wwan/cc-wwan-network-dialog.h |
|
create mode 100644 panels/wwan/cc-wwan-network-dialog.ui |
|
create mode 100644 panels/wwan/cc-wwan-panel.c |
|
create mode 100644 panels/wwan/cc-wwan-panel.h |
|
create mode 100644 panels/wwan/cc-wwan-panel.ui |
|
create mode 100644 panels/wwan/cc-wwan-sim-lock-dialog.c |
|
create mode 100644 panels/wwan/cc-wwan-sim-lock-dialog.h |
|
create mode 100644 panels/wwan/cc-wwan-sim-lock-dialog.ui |
|
create mode 100644 panels/wwan/gnome-wwan-panel.desktop.in.in |
|
create mode 100644 panels/wwan/meson.build |
|
create mode 100644 panels/wwan/wwan.gresource.xml |
|
|
|
diff --git a/meson.build b/meson.build |
|
index 900216962..75487603b 100644 |
|
--- a/meson.build |
|
+++ b/meson.build |
|
@@ -228,6 +228,10 @@ config_h.set('BUILD_NETWORK', host_is_linux, |
|
description: 'Define to 1 to build the Network panel') |
|
config_h.set('HAVE_NETWORK_MANAGER', host_is_linux, |
|
description: 'Define to 1 if NetworkManager is available') |
|
+config_h.set('BUILD_WWAN', host_is_linux, |
|
+ description: 'Define to 1 to build the WWan panel') |
|
+config_h.set('HAVE_WWAN', host_is_linux, |
|
+ description: 'Define to 1 if WWan is available') |
|
|
|
if host_is_linux_not_s390 |
|
# gnome-bluetooth |
|
diff --git a/panels/meson.build b/panels/meson.build |
|
index 2f4fdc5e3..9b9fc34f4 100644 |
|
--- a/panels/meson.build |
|
+++ b/panels/meson.build |
|
@@ -26,7 +26,8 @@ panels = [ |
|
'sound', |
|
'universal-access', |
|
'usage', |
|
- 'user-accounts' |
|
+ 'user-accounts', |
|
+ 'wwan', |
|
] |
|
|
|
if host_is_linux |
|
diff --git a/panels/wwan/cc-wwan-apn-dialog.c b/panels/wwan/cc-wwan-apn-dialog.c |
|
new file mode 100644 |
|
index 000000000..bc5fde283 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-apn-dialog.c |
|
@@ -0,0 +1,424 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-apn-dialog.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-apn-dialog" |
|
+ |
|
+#include <config.h> |
|
+#include <glib/gi18n.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+#include "cc-wwan-data.h" |
|
+#include "list-box-helper.h" |
|
+#include "cc-wwan-apn-dialog.h" |
|
+#include "cc-wwan-resources.h" |
|
+ |
|
+/** |
|
+ * @short_description: Dialog to manage Internet Access Points |
|
+ */ |
|
+ |
|
+struct _CcWwanApnDialog |
|
+{ |
|
+ GtkDialog parent_instance; |
|
+ |
|
+ GtkButton *add_button; |
|
+ GtkButton *back_button; |
|
+ GtkButton *save_button; |
|
+ GtkEntry *apn_entry; |
|
+ GtkEntry *name_entry; |
|
+ GtkEntry *password_entry; |
|
+ GtkEntry *username_entry; |
|
+ GtkGrid *apn_edit_view; |
|
+ GtkListBox *apn_list; |
|
+ GtkRadioButton *apn_radio_button; |
|
+ GtkScrolledWindow *apn_list_view; |
|
+ GtkStack *apn_settings_stack; |
|
+ |
|
+ CcWwanData *wwan_data; |
|
+ CcWwanDataApn *apn_to_save; /* The APN currently being edited */ |
|
+ CcWwanDevice *device; |
|
+ |
|
+ gboolean enable_data; |
|
+ gboolean enable_roaming; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanApnDialog, cc_wwan_apn_dialog, GTK_TYPE_DIALOG) |
|
+ |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_DEVICE, |
|
+ N_PROPS |
|
+}; |
|
+ |
|
+static GParamSpec *properties[N_PROPS]; |
|
+ |
|
+#define CC_TYPE_WWAN_APN_ROW (cc_wwan_apn_row_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanApnRow, cc_wwan_apn_row, CC, WWAN_APN_ROW, GtkListBoxRow) |
|
+ |
|
+struct _CcWwanApnRow |
|
+{ |
|
+ GtkListBoxRow parent_instance; |
|
+ GtkRadioButton *radio_button; |
|
+ CcWwanDataApn *apn; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanApnRow, cc_wwan_apn_row, GTK_TYPE_LIST_BOX_ROW) |
|
+ |
|
+static void |
|
+cc_wwan_apn_row_finalize (GObject *object) |
|
+{ |
|
+ CcWwanApnRow *row = (CcWwanApnRow *)object; |
|
+ |
|
+ g_clear_object (&row->apn); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_apn_row_parent_class)->finalize (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_row_class_init (CcWwanApnRowClass *klass) |
|
+{ |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->finalize = cc_wwan_apn_row_finalize; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_row_init (CcWwanApnRow *row) |
|
+{ |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_back_clicked_cb (CcWwanApnDialog *self) |
|
+{ |
|
+ GtkWidget *view; |
|
+ |
|
+ view = gtk_stack_get_visible_child (self->apn_settings_stack); |
|
+ |
|
+ if (view == GTK_WIDGET (self->apn_edit_view)) |
|
+ { |
|
+ gtk_widget_hide (GTK_WIDGET (self->save_button)); |
|
+ gtk_widget_show (GTK_WIDGET (self->add_button)); |
|
+ gtk_stack_set_visible_child (self->apn_settings_stack, |
|
+ GTK_WIDGET (self->apn_list_view)); |
|
+ } |
|
+ else |
|
+ { |
|
+ gtk_widget_hide (GTK_WIDGET (self)); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_add_clicked_cb (CcWwanApnDialog *self) |
|
+{ |
|
+ gtk_entry_set_text (self->name_entry, ""); |
|
+ gtk_entry_set_text (self->apn_entry, ""); |
|
+ gtk_entry_set_text (self->username_entry, ""); |
|
+ gtk_entry_set_text (self->password_entry, ""); |
|
+ |
|
+ gtk_widget_hide (GTK_WIDGET (self->add_button)); |
|
+ gtk_widget_show (GTK_WIDGET (self->save_button)); |
|
+ self->apn_to_save = NULL; |
|
+ gtk_stack_set_visible_child (self->apn_settings_stack, |
|
+ GTK_WIDGET (self->apn_edit_view)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_save_clicked_cb (CcWwanApnDialog *self) |
|
+{ |
|
+ const gchar *name, *apn_name; |
|
+ CcWwanDataApn *apn; |
|
+ |
|
+ apn = self->apn_to_save; |
|
+ self->apn_to_save = NULL; |
|
+ |
|
+ name = gtk_entry_get_text (self->name_entry); |
|
+ apn_name = gtk_entry_get_text (self->apn_entry); |
|
+ |
|
+ if (!apn) |
|
+ apn = cc_wwan_data_apn_new (); |
|
+ |
|
+ cc_wwan_data_apn_set_name (apn, name); |
|
+ cc_wwan_data_apn_set_apn (apn, apn_name); |
|
+ cc_wwan_data_apn_set_username (apn, gtk_entry_get_text (self->username_entry)); |
|
+ cc_wwan_data_apn_set_password (apn, gtk_entry_get_text (self->password_entry)); |
|
+ |
|
+ cc_wwan_data_save_apn (self->wwan_data, apn, NULL, NULL, NULL); |
|
+ |
|
+ gtk_widget_hide (GTK_WIDGET (self->save_button)); |
|
+ gtk_stack_set_visible_child (self->apn_settings_stack, |
|
+ GTK_WIDGET (self->apn_list_view)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_entry_changed_cb (CcWwanApnDialog *self) |
|
+{ |
|
+ GtkWidget *widget; |
|
+ const gchar *str; |
|
+ gboolean valid_name, valid_apn; |
|
+ |
|
+ widget = GTK_WIDGET (self->name_entry); |
|
+ str = gtk_entry_get_text (self->name_entry); |
|
+ valid_name = str && *str; |
|
+ |
|
+ if (valid_name) |
|
+ gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "error"); |
|
+ else |
|
+ gtk_style_context_add_class (gtk_widget_get_style_context (widget), "error"); |
|
+ |
|
+ widget = GTK_WIDGET (self->apn_entry); |
|
+ str = gtk_entry_get_text (self->apn_entry); |
|
+ valid_apn = str && *str; |
|
+ |
|
+ if (valid_apn) |
|
+ gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "error"); |
|
+ else |
|
+ gtk_style_context_add_class (gtk_widget_get_style_context (widget), "error"); |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->save_button), valid_name && valid_apn); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_activated_cb (CcWwanApnDialog *self, |
|
+ CcWwanApnRow *row) |
|
+{ |
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (row->radio_button), TRUE); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_changed_cb (CcWwanApnDialog *self, |
|
+ GtkWidget *widget) |
|
+{ |
|
+ CcWwanApnRow *row; |
|
+ |
|
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) |
|
+ return; |
|
+ |
|
+ widget = gtk_widget_get_ancestor (widget, CC_TYPE_WWAN_APN_ROW); |
|
+ row = CC_WWAN_APN_ROW (widget); |
|
+ |
|
+ if (cc_wwan_data_set_default_apn (self->wwan_data, row->apn)) |
|
+ cc_wwan_data_save_settings (self->wwan_data, NULL, NULL, NULL); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_edit_clicked_cb (CcWwanApnDialog *self, |
|
+ GtkButton *button) |
|
+{ |
|
+ CcWwanDataApn *apn; |
|
+ CcWwanApnRow *row; |
|
+ GtkWidget *widget; |
|
+ |
|
+ widget = gtk_widget_get_ancestor (GTK_WIDGET (button), CC_TYPE_WWAN_APN_ROW); |
|
+ row = CC_WWAN_APN_ROW (widget); |
|
+ apn = row->apn; |
|
+ self->apn_to_save = apn; |
|
+ |
|
+ gtk_widget_show (GTK_WIDGET (self->save_button)); |
|
+ gtk_widget_hide (GTK_WIDGET (self->add_button)); |
|
+ |
|
+ gtk_entry_set_text (self->name_entry, cc_wwan_data_apn_get_name (apn)); |
|
+ gtk_entry_set_text (self->apn_entry, cc_wwan_data_apn_get_apn (apn)); |
|
+ gtk_entry_set_text (self->username_entry, cc_wwan_data_apn_get_username (apn)); |
|
+ gtk_entry_set_text (self->password_entry, cc_wwan_data_apn_get_password (apn)); |
|
+ |
|
+ gtk_stack_set_visible_child (self->apn_settings_stack, |
|
+ GTK_WIDGET (self->apn_edit_view)); |
|
+} |
|
+ |
|
+static GtkWidget * |
|
+cc_wwan_apn_dialog_row_new (CcWwanDataApn *apn, |
|
+ CcWwanApnDialog *self) |
|
+{ |
|
+ CcWwanApnRow *row; |
|
+ GtkWidget *grid, *name_label, *apn_label, *radio, *edit_button; |
|
+ GtkStyleContext *context; |
|
+ |
|
+ row = g_object_new (CC_TYPE_WWAN_APN_ROW, NULL); |
|
+ |
|
+ grid = g_object_new (GTK_TYPE_GRID, |
|
+ "margin-top", 6, |
|
+ "margin-bottom", 6, |
|
+ "margin-start", 6, |
|
+ "margin-end", 6, |
|
+ NULL); |
|
+ |
|
+ radio = gtk_radio_button_new_from_widget (self->apn_radio_button); |
|
+ row->radio_button = GTK_RADIO_BUTTON (radio); |
|
+ gtk_widget_set_margin_end (radio, 12); |
|
+ gtk_grid_attach (GTK_GRID (grid), radio, 0, 0, 1, 2); |
|
+ row->apn = g_object_ref (apn); |
|
+ |
|
+ if (cc_wwan_data_get_default_apn (self->wwan_data) == apn) |
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE); |
|
+ g_signal_connect_object (radio, "toggled", |
|
+ G_CALLBACK (cc_wwan_apn_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ name_label = gtk_label_new (cc_wwan_data_apn_get_name (apn)); |
|
+ gtk_widget_set_halign (name_label, GTK_ALIGN_START); |
|
+ gtk_widget_set_hexpand (name_label, TRUE); |
|
+ gtk_grid_attach (GTK_GRID (grid), name_label, 1, 0, 1, 1); |
|
+ |
|
+ apn_label = gtk_label_new (cc_wwan_data_apn_get_apn (apn)); |
|
+ gtk_widget_set_halign (apn_label, GTK_ALIGN_START); |
|
+ context = gtk_widget_get_style_context (apn_label); |
|
+ gtk_style_context_add_class (context, "dim-label"); |
|
+ gtk_grid_attach (GTK_GRID (grid), apn_label, 1, 1, 1, 1); |
|
+ |
|
+ edit_button = gtk_button_new_from_icon_name ("emblem-system-symbolic", |
|
+ GTK_ICON_SIZE_BUTTON); |
|
+ g_signal_connect_object (edit_button, "clicked", |
|
+ G_CALLBACK (cc_wwan_apn_edit_clicked_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ gtk_grid_attach (GTK_GRID (grid), edit_button, 2, 0, 1, 2); |
|
+ |
|
+ gtk_container_add (GTK_CONTAINER (row), grid); |
|
+ gtk_widget_show_all (GTK_WIDGET (row)); |
|
+ |
|
+ return GTK_WIDGET (row); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_dialog_set_property (GObject *object, |
|
+ guint prop_id, |
|
+ const GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanApnDialog *self = (CcWwanApnDialog *)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_apn_dialog_constructed (GObject *object) |
|
+{ |
|
+ CcWwanApnDialog *self = (CcWwanApnDialog *)object; |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_apn_dialog_parent_class)->constructed (object); |
|
+ |
|
+ self->wwan_data = cc_wwan_device_get_data (self->device); |
|
+ |
|
+ gtk_list_box_bind_model (self->apn_list, |
|
+ cc_wwan_data_get_apn_list (self->wwan_data), |
|
+ (GtkListBoxCreateWidgetFunc)cc_wwan_apn_dialog_row_new, |
|
+ self, NULL); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_dialog_dispose (GObject *object) |
|
+{ |
|
+ CcWwanApnDialog *self = (CcWwanApnDialog *)object; |
|
+ |
|
+ g_clear_object (&self->device); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_apn_dialog_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+cc_wwan_apn_dialog_show (GtkWidget *widget) |
|
+{ |
|
+ CcWwanApnDialog *self = (CcWwanApnDialog *)widget; |
|
+ |
|
+ gtk_widget_show (GTK_WIDGET (self->add_button)); |
|
+ gtk_widget_hide (GTK_WIDGET (self->save_button)); |
|
+ gtk_stack_set_visible_child (self->apn_settings_stack, |
|
+ GTK_WIDGET (self->apn_list_view)); |
|
+ |
|
+ GTK_WIDGET_CLASS (cc_wwan_apn_dialog_parent_class)->show (widget); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_dialog_class_init (CcWwanApnDialogClass *klass) |
|
+{ |
|
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->set_property = cc_wwan_apn_dialog_set_property; |
|
+ object_class->constructed = cc_wwan_apn_dialog_constructed; |
|
+ object_class->dispose = cc_wwan_apn_dialog_dispose; |
|
+ |
|
+ widget_class->show = cc_wwan_apn_dialog_show; |
|
+ |
|
+ 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-apn-dialog.ui"); |
|
+ |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, add_button); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, apn_edit_view); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, apn_entry); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, apn_list); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, apn_list_view); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, apn_radio_button); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, apn_settings_stack); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, back_button); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, name_entry); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, password_entry); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, save_button); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanApnDialog, username_entry); |
|
+ |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_apn_back_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_apn_add_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_apn_save_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_apn_entry_changed_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_apn_activated_cb); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_apn_dialog_init (CcWwanApnDialog *self) |
|
+{ |
|
+ gtk_widget_init_template (GTK_WIDGET (self)); |
|
+} |
|
+ |
|
+CcWwanApnDialog * |
|
+cc_wwan_apn_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device) |
|
+{ |
|
+ g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL); |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (device), NULL); |
|
+ |
|
+ return g_object_new (CC_TYPE_WWAN_APN_DIALOG, |
|
+ "transient-for", parent_window, |
|
+ "use-header-bar", 1, |
|
+ "device", device, |
|
+ NULL); |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-apn-dialog.h b/panels/wwan/cc-wwan-apn-dialog.h |
|
new file mode 100644 |
|
index 000000000..0e9885836 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-apn-dialog.h |
|
@@ -0,0 +1,40 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-apn-dialog.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <handy.h> |
|
+#include <shell/cc-panel.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_TYPE_WWAN_APN_DIALOG (cc_wwan_apn_dialog_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanApnDialog, cc_wwan_apn_dialog, CC, WWAN_APN_DIALOG, GtkDialog) |
|
+ |
|
+CcWwanApnDialog *cc_wwan_apn_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-apn-dialog.ui b/panels/wwan/cc-wwan-apn-dialog.ui |
|
new file mode 100644 |
|
index 000000000..fb8432bc6 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-apn-dialog.ui |
|
@@ -0,0 +1,249 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<interface> |
|
+ <template class="CcWwanApnDialog" parent="GtkDialog"> |
|
+ <property name="default-height">480</property> |
|
+ <property name="default-width">360</property> |
|
+ <signal name="delete-event" handler="gtk_widget_hide_on_delete"/> |
|
+ |
|
+ <child type="titlebar"> |
|
+ <object class="GtkHeaderBar"> |
|
+ <property name="visible">1</property> |
|
+ <property name="title" translatable="yes">Access Points</property> |
|
+ |
|
+ <!-- Back button --> |
|
+ <child> |
|
+ <object class="GtkButton" id="back_button"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <signal name="clicked" handler="cc_wwan_apn_back_clicked_cb" swapped="yes" /> |
|
+ <child internal-child="accessible"> |
|
+ <object class="AtkObject"> |
|
+ <property name="accessible-name" translatable="yes">Back</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">go-previous-symbolic</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="pack-type">start</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Add button --> |
|
+ <child> |
|
+ <object class="GtkButton" id="add_button"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <signal name="clicked" handler="cc_wwan_apn_add_clicked_cb" swapped="yes" /> |
|
+ <child internal-child="accessible"> |
|
+ <object class="AtkObject"> |
|
+ <property name="accessible-name" translatable="yes">Add</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">list-add-symbolic</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="pack-type">end</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Save button --> |
|
+ <child> |
|
+ <object class="GtkButton" id="save_button"> |
|
+ <property name="visible">0</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Save</property> |
|
+ <signal name="clicked" handler="cc_wwan_apn_save_clicked_cb" swapped="yes" /> |
|
+ <style> |
|
+ <class name="default" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="pack-type">end</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <child internal-child="vbox"> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="border-width">0</property> |
|
+ <property name="width-request">340</property> |
|
+ <property name="height-request">360</property> |
|
+ |
|
+ <child> |
|
+ <object class="HdyClamp"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-top">32</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ |
|
+ <child> |
|
+ <object class="GtkStack" id="apn_settings_stack"> |
|
+ <property name="visible">1</property> |
|
+ <property name="transition-type">slide-left-right</property> |
|
+ |
|
+ <!-- Access Point List --> |
|
+ <child> |
|
+ <object class="GtkScrolledWindow" id="apn_list_view"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-start">18</property> |
|
+ <property name="margin-end">18</property> |
|
+ <child> |
|
+ <object class="GtkListBox" id="apn_list"> |
|
+ <property name="visible">1</property> |
|
+ <property name="valign">start</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <signal name="row-activated" handler="cc_wwan_apn_activated_cb" swapped="yes" /> |
|
+ <style> |
|
+ <class name="content" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <child> |
|
+ <object class="GtkGrid" id="apn_edit_view"> |
|
+ <property name="visible">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ <property name="expand">1</property> |
|
+ <property name="margin-start">18</property> |
|
+ <property name="margin-end">18</property> |
|
+ <property name="row-spacing">6</property> |
|
+ <property name="column-spacing">12</property> |
|
+ |
|
+ <!-- Name --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">end</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="label" translatable="yes">Name</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">0</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkEntry" id="name_entry"> |
|
+ <property name="visible">1</property> |
|
+ <property name="hexpand">1</property> |
|
+ <signal name="changed" handler="cc_wwan_apn_entry_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">0</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- APN --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">end</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="label" translatable="yes">APN</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">1</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkEntry" id="apn_entry"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">12</property> |
|
+ <signal name="changed" handler="cc_wwan_apn_entry_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">1</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Username --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">end</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="label" translatable="yes">Username</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkEntry" id="username_entry"> |
|
+ <property name="visible">1</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Password --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">end</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="label" translatable="yes">Passsword</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">3</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkEntry" id="password_entry"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">12</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">3</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> <!-- ./GtkStack apn_settings_stack --> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> <!-- ./internal-child --> |
|
+ |
|
+ </template> |
|
+ |
|
+ <!-- A simple hack to create a radio button group --> |
|
+ <object class="GtkRadioButton" id="apn_radio_button" /> |
|
+</interface> |
|
diff --git a/panels/wwan/cc-wwan-data.c b/panels/wwan/cc-wwan-data.c |
|
new file mode 100644 |
|
index 000000000..0be8f3403 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-data.c |
|
@@ -0,0 +1,1446 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-data.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-data" |
|
+ |
|
+#ifdef HAVE_CONFIG_H |
|
+# include <config.h> |
|
+#endif |
|
+ |
|
+#define _GNU_SOURCE |
|
+#include <string.h> |
|
+#include <glib/gi18n.h> |
|
+#include <nma-mobile-providers.h> |
|
+ |
|
+#include "cc-wwan-data.h" |
|
+ |
|
+/** |
|
+ * @short_description: Device Internet Data Object |
|
+ * @include: "cc-wwan-device-data.h" |
|
+ * |
|
+ * #CcWwanData represents the data object of the given |
|
+ * #CcWwanDevice. Please note that while #CcWWanDevice |
|
+ * is bound to the hardware device, #CcWwanData may also |
|
+ * depend on the inserted SIM (if supported). So the state |
|
+ * of #CcWwanData changes when SIM is changed. |
|
+ */ |
|
+ |
|
+/* Priority for connections. larger the number, lower the priority */ |
|
+#define CC_WWAN_DNS_PRIORITY_LOW (20) |
|
+#define CC_WWAN_DNS_PRIORITY_HIGH (15) |
|
+ |
|
+/* These are to be set as route metric */ |
|
+#define CC_WWAN_ROUTE_PRIORITY_LOW (1050) |
|
+#define CC_WWAN_ROUTE_PRIORITY_HIGH (1040) |
|
+ |
|
+struct _CcWwanData |
|
+{ |
|
+ GObject parent_instance; |
|
+ |
|
+ MMObject *mm_object; |
|
+ MMModem *modem; |
|
+ MMSim *sim; |
|
+ gchar *sim_id; |
|
+ |
|
+ gchar *operator_code; /* MCCMNC */ |
|
+ GError *error; |
|
+ |
|
+ NMClient *nm_client; |
|
+ NMDevice *nm_device; |
|
+ NMAMobileProvidersDatabase *apn_db; |
|
+ NMAMobileProvider *apn_provider; |
|
+ CcWwanDataApn *default_apn; |
|
+ CcWwanDataApn *old_default_apn; |
|
+ GListStore *apn_list; |
|
+ NMActiveConnection *active_connection; |
|
+ |
|
+ gint priority; |
|
+ gboolean data_enabled; /* autoconnect enabled */ |
|
+ gboolean home_only; /* Data roaming */ |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanData, cc_wwan_data, G_TYPE_OBJECT) |
|
+ |
|
+/* |
|
+ * Default Access Point Settings Logic: |
|
+ * For a provided SIM, all the APNs available from NetworkManager |
|
+ * that matches the given SIM identifier (ICCID, available via |
|
+ * mm_sim_get_identifier() or similar gdbus API) is loaded for |
|
+ * the Device (In NetworkManager, it is saved as ‘sim-id’, if |
|
+ * present). At a time, only one connection will be bound to |
|
+ * a device. If there are more than one match, the item with |
|
+ * the highest ‘route-metric’ is taken. If more matches are |
|
+ * still available, the first item is chosen. |
|
+ * |
|
+ * Populating All available APNs: |
|
+ * All Possible APNs for the given sim are populated the following |
|
+ * way (A list of all the following avoiding duplicates) |
|
+ * 1. The above mentioned “Default Access Point Settings Logic” |
|
+ * 2. Get All saved Network Manager connections with the |
|
+ * provided MCCMNC of the given SIM |
|
+ * 3. Get All possible APNs for the MCCMNC from mobile-provider-info |
|
+ * |
|
+ * Testing if data is enabled: |
|
+ * Check if any of the items from step 1 have ‘autoconnect’ set |
|
+ * |
|
+ * Checking/Setting current SIM for data (in case of multiple SIM): |
|
+ * Since other networks (like wifi, ethernet) should have higher |
|
+ * priorities we use a negative number for priority. |
|
+ * 1. All APNs by default have priority CC_WWAN_APN_PRIORITY_LOW |
|
+ * 2. APN of selected SIM for active data have priority of |
|
+ * CC_WWAN_APN_PRIORITY_HIGH |
|
+ * |
|
+ * XXX: Since users may create custom APNs via nmtui or like tools |
|
+ * we may have to check if there are some inconsistencies with APNs |
|
+ * available in NetworkManager, and ask user if they have to reset |
|
+ * the APNs that have invalid settings (basically, we care only APNs |
|
+ * that are set to have ‘autoconnect’ enabled, and all we need is to |
|
+ * disable autoconnect). We won’t interfere CDMA/EVDO networks. |
|
+ */ |
|
+struct _CcWwanDataApn { |
|
+ GObject parent_instance; |
|
+ |
|
+ /* Set if the APN is from the mobile-provider-info database */ |
|
+ NMAMobileAccessMethod *access_method; |
|
+ |
|
+ /* Set if the APN is saved in NetworkManager */ |
|
+ NMConnection *nm_connection; |
|
+ NMRemoteConnection *remote_connection; |
|
+ |
|
+ gboolean modified; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanDataApn, cc_wwan_data_apn, G_TYPE_OBJECT) |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_ERROR, |
|
+ PROP_ENABLED, |
|
+ N_PROPS |
|
+}; |
|
+ |
|
+static GParamSpec *properties[N_PROPS]; |
|
+ |
|
+static void |
|
+wwan_data_apn_reset (CcWwanDataApn *apn) |
|
+{ |
|
+ if (!apn) |
|
+ return; |
|
+ |
|
+ g_clear_object (&apn->nm_connection); |
|
+ g_clear_object (&apn->remote_connection); |
|
+} |
|
+ |
|
+static NMConnection * |
|
+wwan_data_get_nm_connection (CcWwanDataApn *apn) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSetting *setting; |
|
+ g_autofree gchar *uuid = NULL; |
|
+ |
|
+ if (apn->nm_connection) |
|
+ return apn->nm_connection; |
|
+ |
|
+ if (apn->remote_connection) |
|
+ return NM_CONNECTION (apn->remote_connection); |
|
+ |
|
+ connection = nm_simple_connection_new (); |
|
+ apn->nm_connection = connection; |
|
+ |
|
+ setting = nm_setting_connection_new (); |
|
+ uuid = nm_utils_uuid_generate (); |
|
+ g_object_set (setting, |
|
+ NM_SETTING_CONNECTION_UUID, uuid, |
|
+ NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME, |
|
+ NULL); |
|
+ nm_connection_add_setting (connection, setting); |
|
+ |
|
+ setting = nm_setting_serial_new (); |
|
+ nm_connection_add_setting (connection, setting); |
|
+ |
|
+ setting = nm_setting_ip4_config_new (); |
|
+ g_object_set (setting, NM_SETTING_IP_CONFIG_METHOD, "auto", NULL); |
|
+ nm_connection_add_setting (connection, setting); |
|
+ |
|
+ nm_connection_add_setting (connection, nm_setting_gsm_new ()); |
|
+ nm_connection_add_setting (connection, nm_setting_ppp_new ()); |
|
+ |
|
+ return apn->nm_connection; |
|
+} |
|
+ |
|
+static gboolean |
|
+wwan_data_apn_are_same (NMRemoteConnection *remote_connection, |
|
+ NMAMobileAccessMethod *access_method) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSetting *setting; |
|
+ |
|
+ if (!remote_connection) |
|
+ return FALSE; |
|
+ |
|
+ connection = NM_CONNECTION (remote_connection); |
|
+ setting = NM_SETTING (nm_connection_get_setting_gsm (connection)); |
|
+ |
|
+ if (g_strcmp0 (nma_mobile_access_method_get_3gpp_apn (access_method), |
|
+ nm_setting_gsm_get_apn (NM_SETTING_GSM (setting))) != 0) |
|
+ return FALSE; |
|
+ |
|
+ if (g_strcmp0 (nma_mobile_access_method_get_username (access_method), |
|
+ nm_setting_gsm_get_username (NM_SETTING_GSM (setting))) != 0) |
|
+ return FALSE; |
|
+ |
|
+ if (g_strcmp0 (nma_mobile_access_method_get_password (access_method), |
|
+ nm_setting_gsm_get_password (NM_SETTING_GSM (setting))) != 0) |
|
+ return FALSE; |
|
+ |
|
+ return TRUE; |
|
+} |
|
+ |
|
+static CcWwanDataApn * |
|
+wwan_data_find_matching_apn (CcWwanData *self, |
|
+ NMAMobileAccessMethod *access_method) |
|
+{ |
|
+ CcWwanDataApn *apn; |
|
+ guint i, n_items; |
|
+ |
|
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (self->apn_list)); |
|
+ |
|
+ for (i = 0; i < n_items; i++) |
|
+ { |
|
+ apn = g_list_model_get_item (G_LIST_MODEL (self->apn_list), i); |
|
+ |
|
+ if (apn->access_method == access_method) |
|
+ return apn; |
|
+ |
|
+ if (wwan_data_apn_are_same (apn->remote_connection, |
|
+ access_method)) |
|
+ return apn; |
|
+ |
|
+ g_object_unref (apn); |
|
+ } |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+static gboolean |
|
+wwan_data_nma_method_is_mms (NMAMobileAccessMethod *method) |
|
+{ |
|
+ const char *str; |
|
+ |
|
+ str = nma_mobile_access_method_get_3gpp_apn (method); |
|
+ if (str && strcasestr (str, "mms")) |
|
+ return TRUE; |
|
+ |
|
+ str = nma_mobile_access_method_get_name (method); |
|
+ if (str && strcasestr (str, "mms")) |
|
+ return TRUE; |
|
+ |
|
+ return FALSE; |
|
+} |
|
+ |
|
+static void |
|
+wwan_data_update_apn_list_db (CcWwanData *self) |
|
+{ |
|
+ GSList *apn_methods = NULL, *l; |
|
+ g_autoptr(GError) error = NULL; |
|
+ guint i = 0; |
|
+ |
|
+ if (!self->sim || !self->operator_code) |
|
+ return; |
|
+ |
|
+ if (!self->apn_list) |
|
+ self->apn_list = g_list_store_new (CC_TYPE_WWAN_DATA_APN); |
|
+ |
|
+ if (!self->apn_db) |
|
+ self->apn_db = nma_mobile_providers_database_new_sync (NULL, NULL, NULL, &error); |
|
+ |
|
+ if (error) |
|
+ { |
|
+ g_warning ("%s", error->message); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (!self->apn_provider) |
|
+ self->apn_provider = nma_mobile_providers_database_lookup_3gpp_mcc_mnc (self->apn_db, |
|
+ self->operator_code); |
|
+ |
|
+ if (self->apn_provider) |
|
+ apn_methods = nma_mobile_provider_get_methods (self->apn_provider); |
|
+ |
|
+ for (l = apn_methods; l; l = l->next, i++) |
|
+ { |
|
+ g_autoptr(CcWwanDataApn) apn = NULL; |
|
+ |
|
+ /* We don’t list MMS APNs */ |
|
+ if (wwan_data_nma_method_is_mms (l->data)) |
|
+ continue; |
|
+ |
|
+ apn = wwan_data_find_matching_apn (self, l->data); |
|
+ |
|
+ /* Prepend the item in order */ |
|
+ if (!apn) |
|
+ { |
|
+ apn = cc_wwan_data_apn_new (); |
|
+ g_list_store_insert (self->apn_list, i, apn); |
|
+ } |
|
+ |
|
+ apn->access_method = l->data; |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+wwan_data_update_apn_list (CcWwanData *self) |
|
+{ |
|
+ const GPtrArray *nm_connections; |
|
+ guint i; |
|
+ |
|
+ if (self->apn_list || !self->sim) |
|
+ return; |
|
+ |
|
+ if (!self->apn_list) |
|
+ self->apn_list = g_list_store_new (CC_TYPE_WWAN_DATA_APN); |
|
+ |
|
+ if (self->nm_device) |
|
+ { |
|
+ nm_connections = nm_device_get_available_connections (self->nm_device); |
|
+ |
|
+ for (i = 0; i < nm_connections->len; i++) |
|
+ { |
|
+ g_autoptr(CcWwanDataApn) apn = NULL; |
|
+ |
|
+ apn = cc_wwan_data_apn_new (); |
|
+ apn->remote_connection = g_object_ref (nm_connections->pdata[i]); |
|
+ g_list_store_append (self->apn_list, apn); |
|
+ |
|
+ /* Load the default APN */ |
|
+ if (!self->default_apn && self->sim_id) |
|
+ { |
|
+ NMSettingConnection *connection_setting; |
|
+ NMSettingIPConfig *ip_setting; |
|
+ NMSettingGsm *setting; |
|
+ NMConnection *connection; |
|
+ const gchar *sim_id; |
|
+ |
|
+ connection = NM_CONNECTION (apn->remote_connection); |
|
+ setting = nm_connection_get_setting_gsm (connection); |
|
+ connection_setting = nm_connection_get_setting_connection (connection); |
|
+ sim_id = nm_setting_gsm_get_sim_id (setting); |
|
+ |
|
+ if (sim_id && *sim_id && g_str_equal (sim_id, self->sim_id)) |
|
+ { |
|
+ self->default_apn = apn; |
|
+ self->home_only = nm_setting_gsm_get_home_only (setting); |
|
+ self->data_enabled = nm_setting_connection_get_autoconnect (connection_setting); |
|
+ |
|
+ /* If any of the APN has a high priority, the device have high priority */ |
|
+ ip_setting = nm_connection_get_setting_ip4_config (connection); |
|
+ if (nm_setting_ip_config_get_route_metric (ip_setting) == CC_WWAN_ROUTE_PRIORITY_HIGH) |
|
+ self->priority = CC_WWAN_APN_PRIORITY_HIGH; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+wwan_device_state_changed_cb (CcWwanData *self) |
|
+{ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ENABLED]); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_get_property (GObject *object, |
|
+ guint prop_id, |
|
+ GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanData *self = (CcWwanData *)object; |
|
+ |
|
+ switch (prop_id) |
|
+ { |
|
+ case PROP_ERROR: |
|
+ g_value_set_boolean (value, self->error != NULL); |
|
+ break; |
|
+ |
|
+ case PROP_ENABLED: |
|
+ g_value_set_boolean (value, cc_wwan_data_get_enabled (self)); |
|
+ break; |
|
+ |
|
+ default: |
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_dispose (GObject *object) |
|
+{ |
|
+ CcWwanData *self = (CcWwanData *)object; |
|
+ |
|
+ g_clear_pointer (&self->sim_id, g_free); |
|
+ g_clear_pointer (&self->operator_code, g_free); |
|
+ g_clear_error (&self->error); |
|
+ g_clear_object (&self->apn_list); |
|
+ g_clear_object (&self->modem); |
|
+ g_clear_object (&self->mm_object); |
|
+ g_clear_object (&self->nm_client); |
|
+ g_clear_object (&self->active_connection); |
|
+ g_clear_object (&self->apn_db); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_data_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_class_init (CcWwanDataClass *klass) |
|
+{ |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->get_property = cc_wwan_data_get_property; |
|
+ object_class->dispose = cc_wwan_data_dispose; |
|
+ |
|
+ properties[PROP_ERROR] = |
|
+ g_param_spec_boolean ("error", |
|
+ "Error", |
|
+ "Set if some Error occurs", |
|
+ FALSE, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_ENABLED] = |
|
+ g_param_spec_boolean ("enabled", |
|
+ "Enabled", |
|
+ "Get if the data is enabled", |
|
+ FALSE, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ g_object_class_install_properties (object_class, N_PROPS, properties); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_init (CcWwanData *self) |
|
+{ |
|
+ self->home_only = TRUE; |
|
+ self->priority = CC_WWAN_APN_PRIORITY_LOW; |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_new: |
|
+ * @mm_object: An #MMObject |
|
+ * @nm_client: An #NMClient |
|
+ * |
|
+ * Create a new device data representing the given |
|
+ * @mm_object. If @mm_object isn’t a 3G/CDMA/LTE |
|
+ * modem, %NULL will be returned |
|
+ * |
|
+ * Returns: A #CcWwanData or %NULL. |
|
+ */ |
|
+CcWwanData * |
|
+cc_wwan_data_new (MMObject *mm_object, |
|
+ NMClient *nm_client) |
|
+{ |
|
+ CcWwanData *self; |
|
+ NMDevice *nm_device = NULL; |
|
+ g_autoptr(MMModem) modem = NULL; |
|
+ NMDeviceModemCapabilities capabilities = 0; |
|
+ |
|
+ g_return_val_if_fail (MM_IS_OBJECT (mm_object), NULL); |
|
+ g_return_val_if_fail (NM_CLIENT (nm_client), NULL); |
|
+ |
|
+ modem = mm_object_get_modem (mm_object); |
|
+ |
|
+ if (modem) |
|
+ nm_device = nm_client_get_device_by_iface (nm_client, |
|
+ mm_modem_get_primary_port (modem)); |
|
+ |
|
+ if (NM_IS_DEVICE_MODEM (nm_device)) |
|
+ capabilities = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (nm_device)); |
|
+ |
|
+ if (!(capabilities & (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS |
|
+ | NM_DEVICE_MODEM_CAPABILITY_LTE))) |
|
+ return NULL; |
|
+ |
|
+ self = g_object_new (CC_TYPE_WWAN_DATA, NULL); |
|
+ |
|
+ self->nm_client = g_object_ref (nm_client); |
|
+ self->mm_object = g_object_ref (mm_object); |
|
+ self->modem = g_steal_pointer (&modem); |
|
+ self->sim = mm_modem_get_sim_sync (self->modem, NULL, NULL); |
|
+ self->sim_id = mm_sim_dup_identifier (self->sim); |
|
+ self->operator_code = mm_sim_dup_operator_identifier (self->sim); |
|
+ self->nm_device = g_object_ref (nm_device); |
|
+ self->active_connection = nm_device_get_active_connection (nm_device); |
|
+ |
|
+ if (!self->operator_code) |
|
+ { |
|
+ MMModem3gpp *modem_3gpp; |
|
+ |
|
+ modem_3gpp = mm_object_peek_modem_3gpp (mm_object); |
|
+ if (modem_3gpp) |
|
+ self->operator_code = mm_modem_3gpp_dup_operator_code (modem_3gpp); |
|
+ } |
|
+ |
|
+ if (self->active_connection) |
|
+ g_object_ref (self->active_connection); |
|
+ |
|
+ g_signal_connect_object (self->nm_device, "notify::state", |
|
+ G_CALLBACK (wwan_device_state_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ wwan_data_update_apn_list (self); |
|
+ wwan_data_update_apn_list_db (self); |
|
+ |
|
+ return self; |
|
+} |
|
+ |
|
+GError * |
|
+cc_wwan_data_get_error (CcWwanData *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL); |
|
+ |
|
+ return self->error; |
|
+} |
|
+ |
|
+const gchar * |
|
+cc_wwan_data_get_simple_html_error (CcWwanData *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL); |
|
+ |
|
+ if (!self->error) |
|
+ return NULL; |
|
+ |
|
+ if (g_error_matches (self->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
|
+ return _("Operation Cancelled"); |
|
+ |
|
+ if (g_error_matches (self->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED)) |
|
+ return _("<b>Error:</b> Access denied changing settings"); |
|
+ |
|
+ if (self->error->domain == MM_MOBILE_EQUIPMENT_ERROR) |
|
+ return _("<b>Error:</b> Mobile Equipment Error"); |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+GListModel * |
|
+cc_wwan_data_get_apn_list (CcWwanData *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL); |
|
+ |
|
+ if (!self->apn_list) |
|
+ wwan_data_update_apn_list (self); |
|
+ |
|
+ return G_LIST_MODEL (self->apn_list); |
|
+} |
|
+ |
|
+static gboolean |
|
+wwan_data_apn_is_new (CcWwanDataApn *apn) |
|
+{ |
|
+ return apn->remote_connection == NULL; |
|
+} |
|
+ |
|
+static void |
|
+wwan_data_update_apn (CcWwanData *self, |
|
+ CcWwanDataApn *apn, |
|
+ NMConnection *connection) |
|
+{ |
|
+ NMSetting *setting; |
|
+ const gchar *name, *username, *password, *apn_name; |
|
+ gint dns_priority, route_metric; |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_connection (connection)); |
|
+ |
|
+ g_object_set (setting, |
|
+ NM_SETTING_CONNECTION_AUTOCONNECT, self->data_enabled, |
|
+ NULL); |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_gsm (connection)); |
|
+ |
|
+ g_object_set (setting, |
|
+ NM_SETTING_GSM_HOME_ONLY, self->home_only, |
|
+ NULL); |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_ip4_config (connection)); |
|
+ if (self->priority == CC_WWAN_APN_PRIORITY_HIGH && |
|
+ self->default_apn == apn) |
|
+ { |
|
+ dns_priority = CC_WWAN_DNS_PRIORITY_HIGH; |
|
+ route_metric = CC_WWAN_ROUTE_PRIORITY_HIGH; |
|
+ } |
|
+ else |
|
+ { |
|
+ dns_priority = CC_WWAN_DNS_PRIORITY_LOW; |
|
+ route_metric = CC_WWAN_ROUTE_PRIORITY_LOW; |
|
+ } |
|
+ |
|
+ g_object_set (setting, |
|
+ NM_SETTING_IP_CONFIG_DNS_PRIORITY, dns_priority, |
|
+ NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64)route_metric, |
|
+ NULL); |
|
+ |
|
+ if (apn->access_method && !apn->remote_connection) |
|
+ { |
|
+ name = nma_mobile_access_method_get_name (apn->access_method); |
|
+ username = nma_mobile_access_method_get_username (apn->access_method); |
|
+ password = nma_mobile_access_method_get_password (apn->access_method); |
|
+ apn_name = nma_mobile_access_method_get_3gpp_apn (apn->access_method); |
|
+ } |
|
+ else |
|
+ { |
|
+ return; |
|
+ } |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_gsm (connection)); |
|
+ g_object_set (setting, |
|
+ NM_SETTING_GSM_USERNAME, username, |
|
+ NM_SETTING_GSM_PASSWORD, password, |
|
+ NM_SETTING_GSM_APN, apn_name, |
|
+ NULL); |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_connection (connection)); |
|
+ |
|
+ g_object_set (setting, |
|
+ NM_SETTING_CONNECTION_ID, name, |
|
+ NULL); |
|
+} |
|
+ |
|
+static gint |
|
+wwan_data_get_apn_index (CcWwanData *self, |
|
+ CcWwanDataApn *apn) |
|
+{ |
|
+ GListModel *model; |
|
+ guint i, n_items; |
|
+ |
|
+ model = G_LIST_MODEL (self->apn_list); |
|
+ n_items = g_list_model_get_n_items (model); |
|
+ |
|
+ for (i = 0; i < n_items; i++) |
|
+ { |
|
+ g_autoptr(CcWwanDataApn) cached_apn = NULL; |
|
+ |
|
+ cached_apn = g_list_model_get_item (model, i); |
|
+ |
|
+ if (apn == cached_apn) |
|
+ return i; |
|
+ } |
|
+ |
|
+ return -1; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_connection_updated_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanData *self; |
|
+ CcWwanDataApn *apn; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ apn = g_task_get_task_data (G_TASK (task)); |
|
+ |
|
+ nm_remote_connection_commit_changes_finish (apn->remote_connection, |
|
+ result, &error); |
|
+ if (!error) |
|
+ { |
|
+ guint apn_index; |
|
+ apn_index = wwan_data_get_apn_index (self, apn); |
|
+ |
|
+ if (apn_index >= 0) |
|
+ g_list_model_items_changed (G_LIST_MODEL (self->apn_list), |
|
+ apn_index, 1, 1); |
|
+ else |
|
+ g_warning ("APN ‘%s’ not in APN list", |
|
+ cc_wwan_data_apn_get_name (apn)); |
|
+ |
|
+ apn->modified = FALSE; |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_new_connection_added_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanData *self; |
|
+ CcWwanDataApn *apn; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ apn = g_task_get_task_data (G_TASK (task)); |
|
+ apn->remote_connection = nm_client_add_connection_finish (self->nm_client, |
|
+ result, &error); |
|
+ if (!error) |
|
+ { |
|
+ apn->modified = FALSE; |
|
+ |
|
+ /* If APN has access method, it’s already on the list */ |
|
+ if (!apn->access_method) |
|
+ { |
|
+ g_list_store_append (self->apn_list, apn); |
|
+ g_object_unref (apn); |
|
+ } |
|
+ |
|
+ g_task_return_pointer (task, apn, NULL); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_data_save_apn (CcWwanData *self, |
|
+ CcWwanDataApn *apn, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ NMConnection *connection = NULL; |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA (self)); |
|
+ g_return_if_fail (CC_IS_WWAN_DATA_APN (apn)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ g_task_set_task_data (task, apn, NULL); |
|
+ |
|
+ connection = wwan_data_get_nm_connection (apn); |
|
+ |
|
+ /* If the item has a remote connection, it should already be saved. |
|
+ * We should save it again only if it got modified */ |
|
+ if (apn->remote_connection && !apn->modified) |
|
+ { |
|
+ g_task_return_pointer (task, apn, NULL); |
|
+ return; |
|
+ } |
|
+ |
|
+ wwan_data_update_apn (self, apn, connection); |
|
+ if (wwan_data_apn_is_new (apn)) |
|
+ { |
|
+ nm_client_add_connection_async (self->nm_client, apn->nm_connection, |
|
+ TRUE, cancellable, |
|
+ cc_wwan_data_new_connection_added_cb, |
|
+ g_steal_pointer (&task)); |
|
+ } |
|
+ else |
|
+ { |
|
+ nm_remote_connection_commit_changes_async (apn->remote_connection, TRUE, |
|
+ cancellable, |
|
+ cc_wwan_data_connection_updated_cb, |
|
+ g_steal_pointer (&task)); |
|
+ } |
|
+} |
|
+ |
|
+CcWwanDataApn * |
|
+cc_wwan_data_save_apn_finish (CcWwanData *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL); |
|
+ g_return_val_if_fail (G_IS_TASK (result), NULL); |
|
+ |
|
+ return g_task_propagate_pointer (G_TASK (result), error); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_activated_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanData *self; |
|
+ NMActiveConnection *connection; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ connection = nm_client_activate_connection_finish (self->nm_client, |
|
+ result, &error); |
|
+ if (connection) |
|
+ { |
|
+ g_set_object (&self->active_connection, connection); |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ |
|
+ if (error) |
|
+ g_warning ("Error: %s", error->message); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_settings_saved_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanData *self; |
|
+ GCancellable *cancellable; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ cancellable = g_task_get_cancellable (G_TASK (task)); |
|
+ |
|
+ if (!cc_wwan_data_save_apn_finish (self, result, &error)) |
|
+ { |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ return; |
|
+ } |
|
+ |
|
+ self->default_apn->modified = FALSE; |
|
+ |
|
+ if (self->data_enabled) |
|
+ { |
|
+ nm_client_activate_connection_async (self->nm_client, |
|
+ NM_CONNECTION (self->default_apn->remote_connection), |
|
+ self->nm_device, |
|
+ NULL, cancellable, |
|
+ cc_wwan_data_activated_cb, |
|
+ g_steal_pointer (&task)); |
|
+ } |
|
+ else |
|
+ { |
|
+ if (nm_device_disconnect (self->nm_device, cancellable, &error)) |
|
+ { |
|
+ g_clear_object (&self->active_connection); |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_save_settings: |
|
+ * @cancellable: (nullable): a #GCancellable or %NULL |
|
+ * @callback: a #GAsyncReadyCallback, or %NULL |
|
+ * @user_data: closure data for @callback |
|
+ * |
|
+ * Save default settings to disk and apply changes. |
|
+ * If the default APN has data enabled, the data is |
|
+ * activated after the settings are saved. |
|
+ * |
|
+ * It’s a programmer error to call this function without |
|
+ * a default APN set. |
|
+ * Finish with cc_wwan_data_save_settings_finish(). |
|
+ */ |
|
+void |
|
+cc_wwan_data_save_settings (CcWwanData *self, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSetting *setting; |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA (self)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ g_return_if_fail (self->default_apn != NULL); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ /* Reset old settings to default value */ |
|
+ if (self->old_default_apn && self->old_default_apn->remote_connection) |
|
+ { |
|
+ connection = NM_CONNECTION (self->old_default_apn->remote_connection); |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_gsm (connection)); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_GSM_HOME_ONLY, TRUE, |
|
+ NM_SETTING_GSM_SIM_ID, NULL, |
|
+ NULL); |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_ip4_config (connection)); |
|
+ g_object_set (setting, |
|
+ NM_SETTING_IP_CONFIG_DNS_PRIORITY, CC_WWAN_DNS_PRIORITY_LOW, |
|
+ NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64)CC_WWAN_ROUTE_PRIORITY_LOW, |
|
+ NULL); |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_connection (connection)); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, |
|
+ NULL); |
|
+ |
|
+ nm_remote_connection_commit_changes (NM_REMOTE_CONNECTION (connection), |
|
+ TRUE, cancellable, NULL); |
|
+ self->old_default_apn->modified = FALSE; |
|
+ self->old_default_apn = NULL; |
|
+ } |
|
+ |
|
+ self->default_apn->modified = TRUE; |
|
+ connection = wwan_data_get_nm_connection (self->default_apn); |
|
+ |
|
+ setting = NM_SETTING (nm_connection_get_setting_gsm (connection)); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_GSM_HOME_ONLY, self->home_only, |
|
+ NM_SETTING_GSM_SIM_ID, self->sim_id, |
|
+ NULL); |
|
+ |
|
+ cc_wwan_data_save_apn (self, self->default_apn, cancellable, |
|
+ cc_wwan_data_settings_saved_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_data_save_settings_finish (CcWwanData *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_data_delete_apn (CcWwanData *self, |
|
+ CcWwanDataApn *apn, |
|
+ GCancellable *cancellable, |
|
+ GError **error) |
|
+{ |
|
+ NMRemoteConnection *connection = NULL; |
|
+ gboolean ret = FALSE; |
|
+ gint apn_index; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE); |
|
+ g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE); |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), FALSE); |
|
+ g_return_val_if_fail (error != NULL, FALSE); |
|
+ |
|
+ apn_index = wwan_data_get_apn_index (self, apn); |
|
+ if (apn_index == -1) |
|
+ { |
|
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, |
|
+ "APN not found for the connection"); |
|
+ return FALSE; |
|
+ } |
|
+ |
|
+ connection = g_steal_pointer (&apn->remote_connection); |
|
+ wwan_data_apn_reset (apn); |
|
+ |
|
+ if (connection) |
|
+ ret = nm_remote_connection_delete (connection, cancellable, error); |
|
+ |
|
+ if (!ret) |
|
+ { |
|
+ apn->remote_connection = connection; |
|
+ *error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, |
|
+ "Deleting APN from NetworkManager failed"); |
|
+ return ret; |
|
+ } |
|
+ |
|
+ g_object_unref (connection); |
|
+ |
|
+ /* We remove the item only if it's not in the mobile provider database */ |
|
+ if (!apn->access_method) |
|
+ { |
|
+ if (self->default_apn == apn) |
|
+ self->default_apn = NULL; |
|
+ |
|
+ g_list_store_remove (self->apn_list, apn_index); |
|
+ |
|
+ return TRUE; |
|
+ } |
|
+ |
|
+ *error = g_error_new (G_IO_ERROR, G_IO_ERROR_READ_ONLY, |
|
+ "Deleting APN from NetworkManager failed"); |
|
+ return FALSE; |
|
+} |
|
+ |
|
+CcWwanDataApn * |
|
+cc_wwan_data_get_default_apn (CcWwanData *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL); |
|
+ |
|
+ return self->default_apn; |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_data_set_default_apn (CcWwanData *self, |
|
+ CcWwanDataApn *apn) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSetting *setting; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE); |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), FALSE); |
|
+ g_return_val_if_fail (self->sim_id != NULL, FALSE); |
|
+ |
|
+ if (self->default_apn == apn) |
|
+ return FALSE; |
|
+ |
|
+ /* |
|
+ * APNs are bound to the SIM, not the modem device. |
|
+ * This will let the APN work if the same SIM inserted |
|
+ * in a different device, and not enable data if a |
|
+ * different SIM is inserted to the modem. |
|
+ */ |
|
+ apn->modified = TRUE; |
|
+ self->old_default_apn = self->default_apn; |
|
+ self->default_apn = apn; |
|
+ connection = wwan_data_get_nm_connection (apn); |
|
+ setting = NM_SETTING (nm_connection_get_setting_gsm (connection)); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_GSM_SIM_ID, self->sim_id, NULL); |
|
+ |
|
+ return TRUE; |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_data_get_enabled (CcWwanData *self) |
|
+{ |
|
+ NMSettingConnection *setting; |
|
+ NMConnection *connection; |
|
+ NMDeviceState state; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE); |
|
+ |
|
+ state = nm_device_get_state (self->nm_device); |
|
+ |
|
+ if (state == NM_DEVICE_STATE_DISCONNECTED || |
|
+ state == NM_DEVICE_STATE_DEACTIVATING) |
|
+ if (nm_device_get_state_reason (self->nm_device) == NM_DEVICE_STATE_REASON_USER_REQUESTED) |
|
+ return FALSE; |
|
+ |
|
+ if (nm_device_get_active_connection (self->nm_device) != NULL) |
|
+ return TRUE; |
|
+ |
|
+ if (!self->default_apn || !self->default_apn->remote_connection) |
|
+ return FALSE; |
|
+ |
|
+ connection = NM_CONNECTION (self->default_apn->remote_connection); |
|
+ setting = nm_connection_get_setting_connection (connection); |
|
+ |
|
+ return nm_setting_connection_get_autoconnect (setting); |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_set_enabled: |
|
+ * @self: A #CcWwanData |
|
+ * @enable_data: whether to enable data |
|
+ * |
|
+ * Enable data for the device. The settings is |
|
+ * saved to disk only after a default APN is set. |
|
+ * |
|
+ * If the data is enabled, the device will automatically |
|
+ * turn data on everytime the same SIM is available. |
|
+ * The data set is bound to the SIM, not the modem device. |
|
+ * |
|
+ * Use @cc_wwan_data_save_apn() with the default APN |
|
+ * to save the changes and really enable/disable data. |
|
+ */ |
|
+void |
|
+cc_wwan_data_set_enabled (CcWwanData *self, |
|
+ gboolean enable_data) |
|
+{ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA (self)); |
|
+ |
|
+ self->data_enabled = !!enable_data; |
|
+ |
|
+ if (self->default_apn) |
|
+ self->default_apn->modified = TRUE; |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_data_get_roaming_enabled (CcWwanData *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE); |
|
+ |
|
+ if (!self->default_apn) |
|
+ return FALSE; |
|
+ |
|
+ return !self->home_only; |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_set_roaming_enabled: |
|
+ * @self: A #CcWwanData |
|
+ * @enable_roaming: whether to enable roaming or not |
|
+ * |
|
+ * Enable roaming for the device. The settings is |
|
+ * saved to disk only after a default APN is set. |
|
+ * |
|
+ * Use @cc_wwan_data_save_apn() with the default APN |
|
+ * to save the changes and really enable/disable data. |
|
+ */ |
|
+void |
|
+cc_wwan_data_set_roaming_enabled (CcWwanData *self, |
|
+ gboolean enable_roaming) |
|
+{ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA (self)); |
|
+ |
|
+ self->home_only = !enable_roaming; |
|
+ |
|
+ if (self->default_apn) |
|
+ self->default_apn->modified = TRUE; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_apn_finalize (GObject *object) |
|
+{ |
|
+ CcWwanDataApn *apn = CC_WWAN_DATA_APN (object); |
|
+ |
|
+ wwan_data_apn_reset (apn); |
|
+ g_clear_pointer (&apn->access_method, |
|
+ nma_mobile_access_method_unref); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_data_parent_class)->finalize (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_apn_class_init (CcWwanDataApnClass *klass) |
|
+{ |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->finalize = cc_wwan_data_apn_finalize; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_apn_init (CcWwanDataApn *apn) |
|
+{ |
|
+} |
|
+ |
|
+CcWwanDataApn * |
|
+cc_wwan_data_apn_new (void) |
|
+{ |
|
+ return g_object_new (CC_TYPE_WWAN_DATA_APN, NULL); |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_get_name: |
|
+ * @apn: A #CcWwanDataApn |
|
+ * |
|
+ * Get the Name of @apn |
|
+ * |
|
+ * Returns: (transfer none): The Name of @apn |
|
+ */ |
|
+const gchar * |
|
+cc_wwan_data_apn_get_name (CcWwanDataApn *apn) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), ""); |
|
+ |
|
+ if (apn->remote_connection) |
|
+ return nm_connection_get_id (NM_CONNECTION (apn->remote_connection)); |
|
+ |
|
+ if (apn->access_method) |
|
+ return nma_mobile_access_method_get_name (apn->access_method); |
|
+ |
|
+ return ""; |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_set_name: |
|
+ * @apn: A #CcWwanDataApn |
|
+ * @name: The name to be given for APN, should not |
|
+ * be empty |
|
+ * |
|
+ * Set the name of @apn to be @name. |
|
+ * |
|
+ * @apn is only modified, use @cc_wwan_data_save_apn() |
|
+ * to save the changes. |
|
+ */ |
|
+void |
|
+cc_wwan_data_apn_set_name (CcWwanDataApn *apn, |
|
+ const gchar *name) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSettingConnection *setting; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA_APN (apn)); |
|
+ g_return_if_fail (name != NULL); |
|
+ g_return_if_fail (*name != '\0'); |
|
+ |
|
+ if (g_str_equal (cc_wwan_data_apn_get_name (apn), name)) |
|
+ return; |
|
+ |
|
+ apn->modified = TRUE; |
|
+ connection = wwan_data_get_nm_connection (apn); |
|
+ setting = nm_connection_get_setting_connection (connection); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_CONNECTION_ID, name, |
|
+ NULL); |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_get_apn: |
|
+ * @apn: A #CcWwanDataApn |
|
+ * |
|
+ * Get the APN of @apn |
|
+ * |
|
+ * Returns: (transfer none): The APN of @apn |
|
+ */ |
|
+const gchar * |
|
+cc_wwan_data_apn_get_apn (CcWwanDataApn *apn) |
|
+{ |
|
+ const gchar *apn_name = ""; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), ""); |
|
+ |
|
+ if (apn->remote_connection) |
|
+ { |
|
+ NMSettingGsm *setting; |
|
+ |
|
+ setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection)); |
|
+ apn_name = nm_setting_gsm_get_apn (setting); |
|
+ } |
|
+ else if (apn->access_method) |
|
+ { |
|
+ apn_name = nma_mobile_access_method_get_3gpp_apn (apn->access_method); |
|
+ } |
|
+ |
|
+ return apn_name ? apn_name : ""; |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_set_apn: |
|
+ * @apn: A #CcWwanDataApn |
|
+ * @apn_name: The apn to be used, should not be |
|
+ * empty |
|
+ * |
|
+ * Set the APN of @apn to @apn_name. @apn_name is |
|
+ * usually a URL like “example.com” or a simple string |
|
+ * like “internet” |
|
+ * |
|
+ * @apn is only modified, use @cc_wwan_data_save_apn() |
|
+ * to save the changes. |
|
+ */ |
|
+void |
|
+cc_wwan_data_apn_set_apn (CcWwanDataApn *apn, |
|
+ const gchar *apn_name) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSettingGsm *setting; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA_APN (apn)); |
|
+ g_return_if_fail (apn_name != NULL); |
|
+ g_return_if_fail (*apn_name != '\0'); |
|
+ |
|
+ if (g_str_equal (cc_wwan_data_apn_get_apn (apn), apn_name)) |
|
+ return; |
|
+ |
|
+ apn->modified = TRUE; |
|
+ connection = wwan_data_get_nm_connection (apn); |
|
+ setting = nm_connection_get_setting_gsm (connection); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_GSM_APN, apn_name, |
|
+ NULL); |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_get_username: |
|
+ * @apn: A #CcWwanDataApn |
|
+ * |
|
+ * Get the Username of @apn |
|
+ * |
|
+ * Returns: (transfer none): The Username of @apn |
|
+ */ |
|
+const gchar * |
|
+cc_wwan_data_apn_get_username (CcWwanDataApn *apn) |
|
+{ |
|
+ const gchar *username = ""; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), ""); |
|
+ |
|
+ if (apn->remote_connection) |
|
+ { |
|
+ NMSettingGsm *setting; |
|
+ |
|
+ setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection)); |
|
+ username = nm_setting_gsm_get_username (setting); |
|
+ } |
|
+ else if (apn->access_method) |
|
+ { |
|
+ username = nma_mobile_access_method_get_username (apn->access_method); |
|
+ } |
|
+ |
|
+ return username ? username : ""; |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_set_username: |
|
+ * @apn: A #CcWwanDataAPN |
|
+ * @username: The username to be used |
|
+ * |
|
+ * Set the Username of @apn to @username. |
|
+ * |
|
+ * @apn is only modified, use @cc_wwan_data_save_apn() |
|
+ * to save the changes. |
|
+ */ |
|
+void |
|
+cc_wwan_data_apn_set_username (CcWwanDataApn *apn, |
|
+ const gchar *username) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSettingGsm *setting; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA_APN (apn)); |
|
+ |
|
+ if (username && !*username) |
|
+ username = NULL; |
|
+ |
|
+ if (g_strcmp0 (cc_wwan_data_apn_get_username (apn), username) == 0) |
|
+ return; |
|
+ |
|
+ apn->modified = TRUE; |
|
+ connection = wwan_data_get_nm_connection (apn); |
|
+ setting = nm_connection_get_setting_gsm (connection); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_GSM_USERNAME, username, |
|
+ NULL); |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_get_password: |
|
+ * @apn: A #CcWwanDataApn |
|
+ * |
|
+ * Get the Password of @apn |
|
+ * |
|
+ * Returns: (transfer none): The Password of @apn |
|
+ */ |
|
+const gchar * |
|
+cc_wwan_data_apn_get_password (CcWwanDataApn *apn) |
|
+{ |
|
+ const gchar *password = ""; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), ""); |
|
+ |
|
+ if (NM_IS_REMOTE_CONNECTION (apn->remote_connection)) |
|
+ { |
|
+ g_autoptr(GVariant) secrets = NULL; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ secrets = nm_remote_connection_get_secrets (NM_REMOTE_CONNECTION (apn->remote_connection), |
|
+ "gsm", NULL, &error); |
|
+ |
|
+ if (!error) |
|
+ nm_connection_update_secrets (NM_CONNECTION (apn->remote_connection), |
|
+ "gsm", secrets, &error); |
|
+ |
|
+ if (error) |
|
+ { |
|
+ g_warning ("Error: %s", error->message); |
|
+ return ""; |
|
+ } |
|
+ } |
|
+ |
|
+ if (apn->remote_connection) |
|
+ { |
|
+ NMSettingGsm *setting; |
|
+ |
|
+ setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection)); |
|
+ password = nm_setting_gsm_get_password (setting); |
|
+ } |
|
+ else if (apn->access_method) |
|
+ { |
|
+ password = nma_mobile_access_method_get_password (apn->access_method); |
|
+ } |
|
+ |
|
+ return password ? password : ""; |
|
+ |
|
+ if (apn->remote_connection) |
|
+ nm_connection_clear_secrets (NM_CONNECTION (apn->remote_connection)); |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_data_apn_set_password: |
|
+ * @apn: A #CcWwanDataApn |
|
+ * @password: The password to be used |
|
+ * |
|
+ * Set the Password of @apn to @password. |
|
+ * |
|
+ * @apn is only modified, use @cc_wwan_data_save_apn() |
|
+ * to save the changes. |
|
+ */ |
|
+void |
|
+cc_wwan_data_apn_set_password (CcWwanDataApn *apn, |
|
+ const gchar *password) |
|
+{ |
|
+ NMConnection *connection; |
|
+ NMSettingGsm *setting; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA_APN (apn)); |
|
+ |
|
+ if (password && !*password) |
|
+ password = NULL; |
|
+ |
|
+ if (g_strcmp0 (cc_wwan_data_apn_get_password (apn), password) == 0) |
|
+ return; |
|
+ |
|
+ apn->modified = TRUE; |
|
+ connection = wwan_data_get_nm_connection (apn); |
|
+ setting = nm_connection_get_setting_gsm (connection); |
|
+ g_object_set (G_OBJECT (setting), |
|
+ NM_SETTING_GSM_PASSWORD, password, |
|
+ NULL); |
|
+} |
|
+ |
|
+gint |
|
+cc_wwan_data_get_priority (CcWwanData *self) |
|
+{ |
|
+ CcWwanDataApn *apn; |
|
+ NMSettingIPConfig *setting; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DATA (self), |
|
+ CC_WWAN_APN_PRIORITY_LOW); |
|
+ |
|
+ apn = self->default_apn; |
|
+ |
|
+ if (!apn || !apn->remote_connection) |
|
+ return CC_WWAN_APN_PRIORITY_LOW; |
|
+ |
|
+ setting = nm_connection_get_setting_ip4_config (NM_CONNECTION (apn->remote_connection)); |
|
+ |
|
+ /* Lower the number, higher the priority */ |
|
+ if (nm_setting_ip_config_get_route_metric (setting) <= CC_WWAN_ROUTE_PRIORITY_HIGH) |
|
+ return CC_WWAN_APN_PRIORITY_HIGH; |
|
+ else |
|
+ return CC_WWAN_APN_PRIORITY_LOW; |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_data_set_priority (CcWwanData *self, |
|
+ int priority) |
|
+{ |
|
+ g_return_if_fail (CC_IS_WWAN_DATA (self)); |
|
+ g_return_if_fail (priority == CC_WWAN_APN_PRIORITY_LOW || |
|
+ priority == CC_WWAN_APN_PRIORITY_HIGH); |
|
+ |
|
+ if (self->priority == priority) |
|
+ return; |
|
+ |
|
+ self->priority = priority; |
|
+ |
|
+ if (self->default_apn) |
|
+ self->default_apn->modified = TRUE; |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-data.h b/panels/wwan/cc-wwan-data.h |
|
new file mode 100644 |
|
index 000000000..9572b862d |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-data.h |
|
@@ -0,0 +1,93 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-data.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <glib-object.h> |
|
+#include <libmm-glib.h> |
|
+#include <NetworkManager.h> |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_WWAN_APN_PRIORITY_LOW (1) |
|
+#define CC_WWAN_APN_PRIORITY_HIGH (2) |
|
+ |
|
+#define CC_TYPE_WWAN_DATA_APN (cc_wwan_data_apn_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanDataApn, cc_wwan_data_apn, CC, WWAN_DATA_APN, GObject) |
|
+ |
|
+#define CC_TYPE_WWAN_DATA (cc_wwan_data_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanData, cc_wwan_data, CC, WWAN_DATA, GObject) |
|
+ |
|
+CcWwanData *cc_wwan_data_new (MMObject *mm_object, |
|
+ NMClient *nm_client); |
|
+GError *cc_wwan_data_get_error (CcWwanData *self); |
|
+const gchar *cc_wwan_data_get_simple_html_error (CcWwanData *self); |
|
+GListModel *cc_wwan_data_get_apn_list (CcWwanData *self); |
|
+void cc_wwan_data_save_apn (CcWwanData *self, |
|
+ CcWwanDataApn *apn, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+CcWwanDataApn *cc_wwan_data_save_apn_finish (CcWwanData *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+void cc_wwan_data_save_settings (CcWwanData *self, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_data_save_settings_finish (CcWwanData *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+gboolean cc_wwan_data_delete_apn (CcWwanData *self, |
|
+ CcWwanDataApn *apn, |
|
+ GCancellable *cancellable, |
|
+ GError **error); |
|
+gboolean cc_wwan_data_set_default_apn (CcWwanData *self, |
|
+ CcWwanDataApn *apn); |
|
+CcWwanDataApn *cc_wwan_data_get_default_apn (CcWwanData *self); |
|
+gboolean cc_wwan_data_get_enabled (CcWwanData *self); |
|
+void cc_wwan_data_set_enabled (CcWwanData *self, |
|
+ gboolean enabled); |
|
+gboolean cc_wwan_data_get_roaming_enabled (CcWwanData *self); |
|
+void cc_wwan_data_set_roaming_enabled (CcWwanData *self, |
|
+ gboolean enable_roaming); |
|
+ |
|
+CcWwanDataApn *cc_wwan_data_apn_new (void); |
|
+const gchar *cc_wwan_data_apn_get_name (CcWwanDataApn *apn); |
|
+void cc_wwan_data_apn_set_name (CcWwanDataApn *apn, |
|
+ const gchar *name); |
|
+const gchar *cc_wwan_data_apn_get_apn (CcWwanDataApn *apn); |
|
+void cc_wwan_data_apn_set_apn (CcWwanDataApn *apn, |
|
+ const gchar *apn_name); |
|
+const gchar *cc_wwan_data_apn_get_username (CcWwanDataApn *apn); |
|
+void cc_wwan_data_apn_set_username (CcWwanDataApn *apn, |
|
+ const gchar *username); |
|
+const gchar *cc_wwan_data_apn_get_password (CcWwanDataApn *apn); |
|
+void cc_wwan_data_apn_set_password (CcWwanDataApn *apn, |
|
+ const gchar *password); |
|
+gint cc_wwan_data_get_priority (CcWwanData *self); |
|
+void cc_wwan_data_set_priority (CcWwanData *self, |
|
+ int priority); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-details-dialog.c b/panels/wwan/cc-wwan-details-dialog.c |
|
new file mode 100644 |
|
index 000000000..59e8dc361 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-details-dialog.c |
|
@@ -0,0 +1,257 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-network-dialog.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-details-dialog" |
|
+ |
|
+#include <config.h> |
|
+#include <glib/gi18n.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+#include "list-box-helper.h" |
|
+#include "cc-wwan-details-dialog.h" |
|
+#include "cc-wwan-resources.h" |
|
+ |
|
+/** |
|
+ * @short_description: Dialog to Show Device Details |
|
+ */ |
|
+ |
|
+struct _CcWwanDetailsDialog |
|
+{ |
|
+ GtkDialog parent_instance; |
|
+ |
|
+ GtkLabel *device_identifier; |
|
+ GtkLabel *device_model; |
|
+ GtkLabel *firmware_version; |
|
+ GtkLabel *identifier_label; |
|
+ GtkLabel *manufacturer; |
|
+ GtkLabel *network_status; |
|
+ GtkLabel *network_type; |
|
+ GtkLabel *operator_name; |
|
+ GtkLabel *own_numbers; |
|
+ GtkLabel *signal_strength; |
|
+ |
|
+ CcWwanDevice *device; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanDetailsDialog, cc_wwan_details_dialog, GTK_TYPE_DIALOG) |
|
+ |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_DEVICE, |
|
+ N_PROPS |
|
+}; |
|
+ |
|
+static GParamSpec *properties[N_PROPS]; |
|
+ |
|
+static void |
|
+cc_wwan_details_update_network_status (CcWwanDetailsDialog *self) |
|
+{ |
|
+ CcWwanState state; |
|
+ |
|
+ g_assert (CC_IS_WWAN_DETAILS_DIALOG (self)); |
|
+ |
|
+ state = cc_wwan_device_get_network_state (self->device); |
|
+ |
|
+ switch (state) |
|
+ { |
|
+ case CC_WWAN_REGISTRATION_STATE_IDLE: |
|
+ gtk_label_set_label (self->network_status, _("Not Registered")); |
|
+ break; |
|
+ |
|
+ case CC_WWAN_REGISTRATION_STATE_REGISTERED: |
|
+ gtk_label_set_label (self->network_status, _("Registered")); |
|
+ break; |
|
+ |
|
+ case CC_WWAN_REGISTRATION_STATE_ROAMING: |
|
+ gtk_label_set_label (self->network_status, _("Roaming")); |
|
+ break; |
|
+ |
|
+ case CC_WWAN_REGISTRATION_STATE_SEARCHING: |
|
+ gtk_label_set_label (self->network_status, _("Searching")); |
|
+ break; |
|
+ |
|
+ case CC_WWAN_REGISTRATION_STATE_DENIED: |
|
+ gtk_label_set_label (self->network_status, _("Denied")); |
|
+ break; |
|
+ |
|
+ default: |
|
+ gtk_label_set_label (self->network_status, _("Unknown")); |
|
+ break; |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_details_signal_changed_cb (CcWwanDetailsDialog *self) |
|
+{ |
|
+ g_autofree gchar *network_type_string = NULL; |
|
+ g_autofree gchar *signal_string = NULL; |
|
+ const gchar *operator_name; |
|
+ |
|
+ g_assert (CC_IS_WWAN_DETAILS_DIALOG (self)); |
|
+ |
|
+ operator_name = cc_wwan_device_get_operator_name (self->device); |
|
+ if (operator_name) |
|
+ gtk_label_set_label (self->operator_name, operator_name); |
|
+ |
|
+ network_type_string = cc_wwan_device_dup_network_type_string (self->device); |
|
+ if (network_type_string) |
|
+ gtk_label_set_label (self->network_type, network_type_string); |
|
+ |
|
+ signal_string = cc_wwan_device_dup_signal_string (self->device); |
|
+ if (signal_string) |
|
+ gtk_label_set_label (self->signal_strength, signal_string); |
|
+ |
|
+ cc_wwan_details_update_network_status (self); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_details_update_hardware_details (CcWwanDetailsDialog *self) |
|
+{ |
|
+ const gchar *str; |
|
+ |
|
+ g_assert (CC_IS_WWAN_DETAILS_DIALOG (self)); |
|
+ |
|
+ str = cc_wwan_device_get_manufacturer (self->device); |
|
+ if (str) |
|
+ gtk_label_set_label (self->manufacturer, str); |
|
+ |
|
+ str = cc_wwan_device_get_model (self->device); |
|
+ if (str) |
|
+ gtk_label_set_label (self->device_model, str); |
|
+ |
|
+ str = cc_wwan_device_get_firmware_version (self->device); |
|
+ if (str) |
|
+ gtk_label_set_label (self->firmware_version, str); |
|
+ |
|
+ str = cc_wwan_device_get_identifier (self->device); |
|
+ if (str) |
|
+ gtk_label_set_label (self->device_identifier, str); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_details_dialog_set_property (GObject *object, |
|
+ guint prop_id, |
|
+ const GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanDetailsDialog *self = CC_WWAN_DETAILS_DIALOG (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_details_dialog_constructed (GObject *object) |
|
+{ |
|
+ CcWwanDetailsDialog *self = CC_WWAN_DETAILS_DIALOG (object); |
|
+ g_autofree char *numbers = NULL; |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_details_dialog_parent_class)->constructed (object); |
|
+ |
|
+ g_signal_connect_object (self->device, "notify::signal", |
|
+ G_CALLBACK (cc_wwan_details_signal_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ numbers = cc_wwan_device_dup_own_numbers (self->device); |
|
+ gtk_widget_set_visible (GTK_WIDGET (self->own_numbers), !!numbers); |
|
+ |
|
+ if (numbers) |
|
+ gtk_label_set_text (self->own_numbers, numbers); |
|
+ |
|
+ cc_wwan_details_signal_changed_cb (self); |
|
+ cc_wwan_details_update_hardware_details (self); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_details_dialog_dispose (GObject *object) |
|
+{ |
|
+ CcWwanDetailsDialog *self = CC_WWAN_DETAILS_DIALOG (object); |
|
+ |
|
+ g_clear_object (&self->device); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_details_dialog_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_details_dialog_class_init (CcWwanDetailsDialogClass *klass) |
|
+{ |
|
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->set_property = cc_wwan_details_dialog_set_property; |
|
+ object_class->constructed = cc_wwan_details_dialog_constructed; |
|
+ object_class->dispose = cc_wwan_details_dialog_dispose; |
|
+ |
|
+ 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-details-dialog.ui"); |
|
+ |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, device_identifier); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, device_model); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, firmware_version); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, identifier_label); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, manufacturer); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, network_status); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, network_type); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, operator_name); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, own_numbers); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanDetailsDialog, signal_strength); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_details_dialog_init (CcWwanDetailsDialog *self) |
|
+{ |
|
+ gtk_widget_init_template (GTK_WIDGET (self)); |
|
+} |
|
+ |
|
+CcWwanDetailsDialog * |
|
+cc_wwan_details_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device) |
|
+{ |
|
+ g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL); |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (device), NULL); |
|
+ |
|
+ return g_object_new (CC_TYPE_WWAN_DETAILS_DIALOG, |
|
+ "transient-for", parent_window, |
|
+ "use-header-bar", 1, |
|
+ "device", device, |
|
+ NULL); |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-details-dialog.h b/panels/wwan/cc-wwan-details-dialog.h |
|
new file mode 100644 |
|
index 000000000..7e7812cde |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-details-dialog.h |
|
@@ -0,0 +1,40 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-details-dialog.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <handy.h> |
|
+#include <shell/cc-panel.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_TYPE_WWAN_DETAILS_DIALOG (cc_wwan_details_dialog_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanDetailsDialog, cc_wwan_details_dialog, CC, WWAN_DETAILS_DIALOG, GtkDialog) |
|
+ |
|
+CcWwanDetailsDialog *cc_wwan_details_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-details-dialog.ui b/panels/wwan/cc-wwan-details-dialog.ui |
|
new file mode 100644 |
|
index 000000000..042d3ee33 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-details-dialog.ui |
|
@@ -0,0 +1,320 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<interface> |
|
+ <template class="CcWwanDetailsDialog" parent="GtkDialog"> |
|
+ <property name="title" translatable="yes">Modem Details</property> |
|
+ <property name="default-height">480</property> |
|
+ <property name="default-width">360</property> |
|
+ <signal name="delete-event" handler="gtk_widget_hide_on_delete"/> |
|
+ |
|
+ <child internal-child="vbox"> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="border-width">0</property> |
|
+ <property name="width-request">340</property> |
|
+ <property name="height-request">360</property> |
|
+ <child> |
|
+ <object class="HdyClamp"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-top">32</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <property name="margin-start">18</property> |
|
+ <property name="margin-end">18</property> |
|
+ |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ |
|
+ <!-- Modem Status Title --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">12</property> |
|
+ <property name="label" translatable="yes">Modem Status</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold"/> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Modem Status Content --> |
|
+ <child> |
|
+ <object class="GtkGrid"> |
|
+ <property name="visible">1</property> |
|
+ <property name="row-spacing">9</property> |
|
+ <property name="column-spacing">6</property> |
|
+ <property name="margin-bottom">24</property> |
|
+ |
|
+ <!-- Carrier --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Carrier</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">0</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="operator_name"> |
|
+ <property name="visible">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">0</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Network Type --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Network Type</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">1</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="network_type"> |
|
+ <property name="visible">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">1</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Signal Strength --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Signal Strength</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="signal_strength"> |
|
+ <property name="visible">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Network Status --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Network Status</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">3</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="network_status"> |
|
+ <property name="visible">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">3</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Own Numbers --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible" bind-source="own_numbers" |
|
+ bind-property="visible" bind-flags="sync-create"/> |
|
+ <property name="label" translatable="yes">Own Number</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">4</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="own_numbers"> |
|
+ <property name="visible">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">4</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Device Details Title --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">12</property> |
|
+ <property name="label" translatable="yes">Device Details</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold"/> |
|
+ </attributes> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">5</property> |
|
+ <property name="width">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Device Details Content --> |
|
+ <!-- Manufacturer --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Manufacturer</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">6</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="manufacturer"> |
|
+ <property name="visible">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">6</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Model --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Model</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">7</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="device_model"> |
|
+ <property name="visible">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <property name="selectable">1</property> |
|
+ <property name="ellipsize">end</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">7</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Firmware version --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Firmware Version</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">8</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="firmware_version"> |
|
+ <property name="visible">1</property> |
|
+ <property name="selectable">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <property name="ellipsize">end</property> |
|
+ <property name="wrap">1</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">8</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- IMEI/ICCID --> |
|
+ <child> |
|
+ <object class="GtkLabel" id="identifier_label"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">IMEI</property> |
|
+ <property name="xalign">1.0</property> |
|
+ <style> |
|
+ <class name="dim-label"/> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">9</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id="device_identifier"> |
|
+ <property name="visible">1</property> |
|
+ <property name="selectable">1</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">9</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> <!-- ./HdyClamp --> |
|
+ </child> |
|
+ </object> |
|
+ </child> <!-- ./internal-child --> |
|
+ |
|
+ </template> |
|
+</interface> |
|
diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c |
|
new file mode 100644 |
|
index 000000000..0a04d3379 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-device-page.c |
|
@@ -0,0 +1,634 @@ |
|
+/* -*- 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.h> |
|
+ |
|
+#include "list-box-helper.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; |
|
+ |
|
+ GtkLabel *notification_label; |
|
+ |
|
+ 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_data_show_apn_dialog (CcWwanDevicePage *self) |
|
+{ |
|
+ GtkWindow *top_level; |
|
+ |
|
+ top_level = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))); |
|
+ |
|
+ if (!self->apn_dialog) |
|
+ self->apn_dialog = cc_wwan_apn_dialog_new (top_level, self->device); |
|
+ |
|
+ 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) |
|
+{ |
|
+ gboolean active; |
|
+ |
|
+ 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); |
|
+ |
|
+ /* 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 void |
|
+wwan_network_settings_activated_cb (CcWwanDevicePage *self, |
|
+ CcListRow *row) |
|
+{ |
|
+ GtkWidget *dialog; |
|
+ GtkWindow *top_level; |
|
+ |
|
+ top_level = GTK_WINDOW (gtk_widget_get_toplevel (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_toplevel (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 ((GtkWidget **)&self->apn_dialog, gtk_widget_destroy); |
|
+ g_clear_pointer ((GtkWidget **)&self->details_dialog, gtk_widget_destroy); |
|
+ g_clear_pointer ((GtkWidget **)&self->network_mode_dialog, gtk_widget_destroy); |
|
+ g_clear_pointer ((GtkWidget **)&self->network_dialog, gtk_widget_destroy); |
|
+ g_clear_pointer ((GtkWidget **)&self->sim_lock_dialog, gtk_widget_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)); |
|
+ |
|
+ gtk_list_box_set_header_func (self->data_settings_list, |
|
+ cc_list_box_update_header_func, |
|
+ NULL, NULL); |
|
+ |
|
+ gtk_list_box_set_header_func (self->network_settings_list, |
|
+ cc_list_box_update_header_func, |
|
+ NULL, NULL); |
|
+ |
|
+ gtk_list_box_set_header_func (self->advanced_settings_list, |
|
+ cc_list_box_update_header_func, |
|
+ NULL, NULL); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_error_changed_cb (CcWwanDevicePage *self) |
|
+{ |
|
+ const gchar *message; |
|
+ |
|
+ message = cc_wwan_device_get_simple_error (self->device); |
|
+ |
|
+ if (!message) |
|
+ return; |
|
+ |
|
+ /* |
|
+ * The label is first set to empty, which will result in |
|
+ * the revealer to be closed. Then the real label is |
|
+ * set. This will animate the revealer which can bring |
|
+ * the user's attention. |
|
+ */ |
|
+ gtk_label_set_label (self->notification_label, ""); |
|
+ gtk_label_set_label (self->notification_label, message); |
|
+} |
|
+ |
|
+CcWwanDevicePage * |
|
+cc_wwan_device_page_new (CcWwanDevice *device, |
|
+ GtkWidget *notification_label) |
|
+{ |
|
+ 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->notification_label = GTK_LABEL (notification_label); |
|
+ |
|
+ 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; |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-device-page.h b/panels/wwan/cc-wwan-device-page.h |
|
new file mode 100644 |
|
index 000000000..923346a89 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-device-page.h |
|
@@ -0,0 +1,42 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-device-page.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <shell/cc-panel.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_TYPE_WWAN_DEVICE_PAGE (cc_wwan_device_page_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanDevicePage, cc_wwan_device_page, CC, WWAN_DEVICE_PAGE, GtkBox) |
|
+ |
|
+CcWwanDevicePage *cc_wwan_device_page_new (CcWwanDevice *device, |
|
+ GtkWidget *notification_label); |
|
+CcWwanDevice *cc_wwan_device_page_get_device (CcWwanDevicePage *self); |
|
+void cc_wwan_device_page_set_sim_index (CcWwanDevicePage *self, |
|
+ gint sim_index); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-device-page.ui b/panels/wwan/cc-wwan-device-page.ui |
|
new file mode 100644 |
|
index 000000000..f77bd707d |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-device-page.ui |
|
@@ -0,0 +1,270 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<interface> |
|
+ <template class="CcWwanDevicePage" parent="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <child> |
|
+ <object class="GtkStack" id="main_stack"> |
|
+ <property name="visible">1</property> |
|
+ <property name="homogeneous">0</property> |
|
+ |
|
+ <!-- SIM not inserted view --> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="expand">1</property> |
|
+ <property name="halign">center</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="orientation">vertical</property> |
|
+ <property name="margin-bottom">64</property> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">auth-sim-missing</property> |
|
+ <property name="pixel-size">192</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="label" translatable="yes">No SIM</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold" /> |
|
+ <attribute name="scale" value="1.2" /> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="label" translatable="yes">Insert a SIM card to use this modem</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">no-sim-view</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- SIM locked view --> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="expand">1</property> |
|
+ <property name="halign">center</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="orientation">vertical</property> |
|
+ <property name="margin-bottom">64</property> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">auth-sim-locked</property> |
|
+ <property name="pixel-size">192</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="label" translatable="yes">SIM Locked</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold" /> |
|
+ <attribute name="scale" value="1.2" /> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkButton" id="unlock_button"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Unlock</property> |
|
+ <signal name="clicked" handler="wwan_device_unlock_clicked_cb" swapped="yes" /> |
|
+ <style> |
|
+ <class name="suggested-action" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">sim-lock-view</property> |
|
+ </packing> |
|
+ </child> <!-- --> |
|
+ |
|
+ <!-- Network Settings --> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-top">18</property> |
|
+ <property name="orientation">vertical</property> |
|
+ |
|
+ <!-- Network Settings Title --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Network</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <property name="margin-bottom">12</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold"/> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Internet settings --> |
|
+ <child> |
|
+ <object class="GtkListBox" id="data_settings_list"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ </style> |
|
+ |
|
+ <!-- Enable/Disable Data --> |
|
+ <child> |
|
+ <object class="CcListRow" id="data_enable_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="show-switch">1</property> |
|
+ <property name="title" translatable="yes">_Mobile Data</property> |
|
+ <property name="subtitle" translatable="yes">Access data using mobile network</property> |
|
+ <signal name="notify::active" handler="wwan_data_settings_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Data Roaming --> |
|
+ <child> |
|
+ <object class="CcListRow" id="data_roaming_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="show-switch">1</property> |
|
+ <property name="title" translatable="yes">_Data Roaming</property> |
|
+ <property name="subtitle" translatable="yes">Use mobile data when roaming</property> |
|
+ <signal name="notify::active" handler="wwan_data_settings_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Network Settings --> |
|
+ <child> |
|
+ <object class="GtkListBox" id="network_settings_list" > |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ </style> |
|
+ <signal name="row-activated" handler="wwan_network_settings_activated_cb" swapped="yes" /> |
|
+ |
|
+ <!-- Network Mode --> |
|
+ <child> |
|
+ <object class="CcListRow" id="network_mode_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="icon-name">go-next-symbolic</property> |
|
+ <property name="title" translatable="yes">_Network Mode</property> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Network --> |
|
+ <child> |
|
+ <object class="CcListRow" id="network_name_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="icon-name">go-next-symbolic</property> |
|
+ <property name="title" translatable="yes">N_etwork</property> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ |
|
+ <!-- Advanced Settings Title --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Advanced</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <property name="margin-bottom">12</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold"/> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Advanced settings --> |
|
+ <child> |
|
+ <object class="GtkListBox" id="advanced_settings_list" > |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ </style> |
|
+ <signal name="row-activated" handler="wwan_advanced_settings_activated_cb" swapped="yes" /> |
|
+ |
|
+ <!-- Accesss Point Settings --> |
|
+ <child> |
|
+ <object class="CcListRow" id="apn_settings_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="icon-name">go-next-symbolic</property> |
|
+ <property name="title" translatable="yes">_Access Point Names</property> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- SIM Lock --> |
|
+ <child> |
|
+ <object class="CcListRow" id="sim_lock_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="icon-name">go-next-symbolic</property> |
|
+ <property name="title" translatable="yes">_SIM Lock</property> |
|
+ <property name="subtitle" translatable="yes">Lock SIM with PIN</property> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Modem Details --> |
|
+ <child> |
|
+ <object class="CcListRow" id="details_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="icon-name">go-next-symbolic</property> |
|
+ <property name="title" translatable="yes">M_odem Details</property> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">settings-view</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> <!-- ./GtkStack main_stack --> |
|
+ </child> |
|
+ </template> |
|
+ <object class="GtkSizeGroup"> |
|
+ <property name="mode">both</property> |
|
+ <widgets> |
|
+ <widget name="apn_settings_row"/> |
|
+ <widget name="sim_lock_row"/> |
|
+ <widget name="details_row"/> |
|
+ </widgets> |
|
+ </object> |
|
+</interface> |
|
diff --git a/panels/wwan/cc-wwan-device.c b/panels/wwan/cc-wwan-device.c |
|
new file mode 100644 |
|
index 000000000..31baff95c |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-device.c |
|
@@ -0,0 +1,1355 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-device.c |
|
+ * |
|
+ * Copyright 2019-2020 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" |
|
+ |
|
+#ifdef HAVE_CONFIG_H |
|
+# include "config.h" |
|
+#endif |
|
+ |
|
+#include <glib/gi18n.h> |
|
+#include <polkit/polkit.h> |
|
+#if defined(HAVE_NETWORK_MANAGER) && defined(BUILD_NETWORK) |
|
+# include <NetworkManager.h> |
|
+# include <nma-mobile-providers.h> |
|
+#endif |
|
+ |
|
+#include "cc-wwan-errors-private.h" |
|
+#include "cc-wwan-device.h" |
|
+ |
|
+/** |
|
+ * @short_description: Device Object |
|
+ * @include: "cc-wwan-device.h" |
|
+ */ |
|
+ |
|
+struct _CcWwanDevice |
|
+{ |
|
+ GObject parent_instance; |
|
+ |
|
+ MMObject *mm_object; |
|
+ MMModem *modem; |
|
+ MMSim *sim; |
|
+ MMModem3gpp *modem_3gpp; |
|
+ |
|
+ const char *operator_code; /* MCCMNC */ |
|
+ GError *error; |
|
+ |
|
+ /* Building with NetworkManager is optional, |
|
+ * so #NMclient type can’t be used here. |
|
+ */ |
|
+ GObject *nm_client; /* An #NMClient */ |
|
+ CcWwanData *wwan_data; |
|
+ |
|
+ gulong modem_3gpp_id; |
|
+ gulong modem_3gpp_locks_id; |
|
+ |
|
+ /* Enabled locks like PIN, PIN2, PUK, etc. */ |
|
+ MMModem3gppFacility locks; |
|
+ |
|
+ CcWwanState registration_state; |
|
+ gboolean network_is_manual; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanDevice, cc_wwan_device, G_TYPE_OBJECT) |
|
+ |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_OPERATOR_NAME, |
|
+ PROP_ENABLED_LOCKS, |
|
+ PROP_ERROR, |
|
+ PROP_HAS_DATA, |
|
+ PROP_NETWORK_MODE, |
|
+ PROP_REGISTRATION_STATE, |
|
+ PROP_SIGNAL, |
|
+ PROP_UNLOCK_REQUIRED, |
|
+ N_PROPS |
|
+}; |
|
+ |
|
+static GParamSpec *properties[N_PROPS]; |
|
+ |
|
+static void |
|
+cc_wwan_device_state_changed_cb (CcWwanDevice *self) |
|
+{ |
|
+ MMModem3gppRegistrationState state; |
|
+ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_OPERATOR_NAME]); |
|
+ |
|
+ state = mm_modem_3gpp_get_registration_state (self->modem_3gpp); |
|
+ |
|
+ switch (state) |
|
+ { |
|
+ case MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN: |
|
+ self->registration_state = CC_WWAN_REGISTRATION_STATE_UNKNOWN; |
|
+ break; |
|
+ |
|
+ case MM_MODEM_3GPP_REGISTRATION_STATE_DENIED: |
|
+ self->registration_state = CC_WWAN_REGISTRATION_STATE_DENIED; |
|
+ break; |
|
+ |
|
+ case MM_MODEM_3GPP_REGISTRATION_STATE_IDLE: |
|
+ self->registration_state = CC_WWAN_REGISTRATION_STATE_IDLE; |
|
+ break; |
|
+ |
|
+ case MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING: |
|
+ self->registration_state = CC_WWAN_REGISTRATION_STATE_SEARCHING; |
|
+ break; |
|
+ |
|
+ case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING: |
|
+ self->registration_state = CC_WWAN_REGISTRATION_STATE_ROAMING; |
|
+ break; |
|
+ |
|
+ default: |
|
+ self->registration_state = CC_WWAN_REGISTRATION_STATE_REGISTERED; |
|
+ break; |
|
+ } |
|
+ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_REGISTRATION_STATE]); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_locks_changed_cb (CcWwanDevice *self) |
|
+{ |
|
+ self->locks = mm_modem_3gpp_get_enabled_facility_locks (self->modem_3gpp); |
|
+ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ENABLED_LOCKS]); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_3gpp_changed_cb (CcWwanDevice *self) |
|
+{ |
|
+ gulong handler_id = 0; |
|
+ |
|
+ if (self->modem_3gpp_id) |
|
+ g_signal_handler_disconnect (self->modem_3gpp, self->modem_3gpp_id); |
|
+ self->modem_3gpp_id = 0; |
|
+ |
|
+ if (self->modem_3gpp_locks_id) |
|
+ g_signal_handler_disconnect (self->modem_3gpp, self->modem_3gpp_locks_id); |
|
+ self->modem_3gpp_locks_id = 0; |
|
+ |
|
+ g_clear_object (&self->modem_3gpp); |
|
+ self->modem_3gpp = mm_object_get_modem_3gpp (self->mm_object); |
|
+ |
|
+ if (self->modem_3gpp) |
|
+ { |
|
+ handler_id = g_signal_connect_object (self->modem_3gpp, "notify::registration-state", |
|
+ G_CALLBACK (cc_wwan_device_state_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ self->modem_3gpp_id = handler_id; |
|
+ |
|
+ handler_id = g_signal_connect_object (self->modem_3gpp, "notify::enabled-facility-locks", |
|
+ G_CALLBACK (cc_wwan_device_locks_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ self->modem_3gpp_locks_id = handler_id; |
|
+ cc_wwan_device_locks_changed_cb (self); |
|
+ cc_wwan_device_state_changed_cb (self); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_signal_quality_changed_cb (CcWwanDevice *self) |
|
+{ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIGNAL]); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_mode_changed_cb (CcWwanDevice *self) |
|
+{ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NETWORK_MODE]); |
|
+} |
|
+ |
|
+static void |
|
+wwan_device_emit_data_changed (CcWwanDevice *self) |
|
+{ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_DATA]); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_unlock_required_cb (CcWwanDevice *self) |
|
+{ |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UNLOCK_REQUIRED]); |
|
+} |
|
+ |
|
+#if defined(HAVE_NETWORK_MANAGER) && defined(BUILD_NETWORK) |
|
+static void |
|
+cc_wwan_device_nm_changed_cb (CcWwanDevice *self, |
|
+ GParamSpec *pspec, |
|
+ NMClient *client) |
|
+{ |
|
+ gboolean nm_is_running; |
|
+ |
|
+ nm_is_running = nm_client_get_nm_running (client); |
|
+ |
|
+ if (!nm_is_running && self->wwan_data != NULL) |
|
+ { |
|
+ g_clear_object (&self->wwan_data); |
|
+ wwan_device_emit_data_changed (self); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_nm_device_added_cb (CcWwanDevice *self, |
|
+ NMDevice *nm_device) |
|
+{ |
|
+ if (!NM_IS_DEVICE_MODEM (nm_device)) |
|
+ return; |
|
+ |
|
+ if(!self->sim || !cc_wwan_device_is_nm_device (self, G_OBJECT (nm_device))) |
|
+ return; |
|
+ |
|
+ self->wwan_data = cc_wwan_data_new (self->mm_object, |
|
+ NM_CLIENT (self->nm_client)); |
|
+ |
|
+ if (self->wwan_data) |
|
+ { |
|
+ g_signal_connect_object (self->wwan_data, "notify::enabled", |
|
+ G_CALLBACK (wwan_device_emit_data_changed), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ wwan_device_emit_data_changed (self); |
|
+ } |
|
+} |
|
+#endif |
|
+ |
|
+static void |
|
+cc_wwan_device_get_property (GObject *object, |
|
+ guint prop_id, |
|
+ GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanDevice *self = (CcWwanDevice *)object; |
|
+ MMModemMode allowed, preferred; |
|
+ |
|
+ switch (prop_id) |
|
+ { |
|
+ case PROP_OPERATOR_NAME: |
|
+ g_value_set_string (value, cc_wwan_device_get_operator_name (self)); |
|
+ break; |
|
+ |
|
+ case PROP_ERROR: |
|
+ g_value_set_boolean (value, self->error != NULL); |
|
+ break; |
|
+ |
|
+ case PROP_HAS_DATA: |
|
+ g_value_set_boolean (value, self->wwan_data != NULL); |
|
+ break; |
|
+ |
|
+ case PROP_ENABLED_LOCKS: |
|
+ g_value_set_int (value, self->locks); |
|
+ break; |
|
+ |
|
+ case PROP_NETWORK_MODE: |
|
+ if (cc_wwan_device_get_current_mode (self, &allowed, &preferred)) |
|
+ g_value_take_string (value, cc_wwan_device_get_string_from_mode (self, allowed, preferred)); |
|
+ break; |
|
+ |
|
+ case PROP_REGISTRATION_STATE: |
|
+ g_value_set_int (value, self->registration_state); |
|
+ break; |
|
+ |
|
+ case PROP_UNLOCK_REQUIRED: |
|
+ g_value_set_int (value, cc_wwan_device_get_lock (self)); |
|
+ break; |
|
+ |
|
+ default: |
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_dispose (GObject *object) |
|
+{ |
|
+ CcWwanDevice *self = (CcWwanDevice *)object; |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ g_clear_object (&self->modem); |
|
+ g_clear_object (&self->mm_object); |
|
+ g_clear_object (&self->sim); |
|
+ g_clear_object (&self->modem_3gpp); |
|
+ |
|
+ g_clear_object (&self->nm_client); |
|
+ g_clear_object (&self->wwan_data); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_device_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_class_init (CcWwanDeviceClass *klass) |
|
+{ |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->get_property = cc_wwan_device_get_property; |
|
+ object_class->dispose = cc_wwan_device_dispose; |
|
+ |
|
+ properties[PROP_OPERATOR_NAME] = |
|
+ g_param_spec_string ("operator-name", |
|
+ "Operator Name", |
|
+ "Operator Name the device is connected to", |
|
+ NULL, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_ENABLED_LOCKS] = |
|
+ g_param_spec_int ("enabled-locks", |
|
+ "Enabled Locks", |
|
+ "Locks Enabled in Modem", |
|
+ MM_MODEM_3GPP_FACILITY_NONE, |
|
+ MM_MODEM_3GPP_FACILITY_CORP_PERS, |
|
+ MM_MODEM_3GPP_FACILITY_NONE, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_ERROR] = |
|
+ g_param_spec_boolean ("error", |
|
+ "Error", |
|
+ "Set if some Error occurs", |
|
+ FALSE, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_HAS_DATA] = |
|
+ g_param_spec_boolean ("has-data", |
|
+ "has-data", |
|
+ "Data for the device", |
|
+ FALSE, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_NETWORK_MODE] = |
|
+ g_param_spec_string ("network-mode", |
|
+ "Network Mode", |
|
+ "A String representing preferred network mode", |
|
+ NULL, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_REGISTRATION_STATE] = |
|
+ g_param_spec_int ("registration-state", |
|
+ "Registration State", |
|
+ "The current network registration state", |
|
+ CC_WWAN_REGISTRATION_STATE_UNKNOWN, |
|
+ CC_WWAN_REGISTRATION_STATE_DENIED, |
|
+ CC_WWAN_REGISTRATION_STATE_UNKNOWN, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_UNLOCK_REQUIRED] = |
|
+ g_param_spec_int ("unlock-required", |
|
+ "Unlock Required", |
|
+ "The Modem lock status changed", |
|
+ MM_MODEM_LOCK_UNKNOWN, |
|
+ MM_MODEM_LOCK_PH_NETSUB_PUK, |
|
+ MM_MODEM_LOCK_UNKNOWN, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ properties[PROP_SIGNAL] = |
|
+ g_param_spec_int ("signal", |
|
+ "Signal", |
|
+ "Get Device Signal", |
|
+ 0, 100, 0, |
|
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
+ |
|
+ g_object_class_install_properties (object_class, N_PROPS, properties); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_init (CcWwanDevice *self) |
|
+{ |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_device_new: |
|
+ * @mm_object: (transfer full): An #MMObject |
|
+ * |
|
+ * Create a new device representing the given |
|
+ * @mm_object. |
|
+ * |
|
+ * Returns: A #CcWwanDevice |
|
+ */ |
|
+CcWwanDevice * |
|
+cc_wwan_device_new (MMObject *mm_object, |
|
+ GObject *nm_client) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ |
|
+ g_return_val_if_fail (MM_IS_OBJECT (mm_object), NULL); |
|
+#if defined(HAVE_NETWORK_MANAGER) && defined(BUILD_NETWORK) |
|
+ g_return_val_if_fail (NM_IS_CLIENT (nm_client), NULL); |
|
+#else |
|
+ g_return_val_if_fail (!nm_client, NULL); |
|
+#endif |
|
+ |
|
+ self = g_object_new (CC_TYPE_WWAN_DEVICE, NULL); |
|
+ |
|
+ self->mm_object = g_object_ref (mm_object); |
|
+ self->modem = mm_object_get_modem (mm_object); |
|
+ self->sim = mm_modem_get_sim_sync (self->modem, NULL, NULL); |
|
+ g_set_object (&self->nm_client, nm_client); |
|
+ if (self->sim) |
|
+ { |
|
+ self->operator_code = mm_sim_get_operator_identifier (self->sim); |
|
+#if defined(HAVE_NETWORK_MANAGER) && defined(BUILD_NETWORK) |
|
+ self->wwan_data = cc_wwan_data_new (mm_object, |
|
+ NM_CLIENT (self->nm_client)); |
|
+#endif |
|
+ } |
|
+ |
|
+ g_signal_connect_object (self->mm_object, "notify::unlock-required", |
|
+ G_CALLBACK (cc_wwan_device_unlock_required_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ if (self->wwan_data) |
|
+ g_signal_connect_object (self->wwan_data, "notify::enabled", |
|
+ G_CALLBACK (wwan_device_emit_data_changed), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+#if defined(HAVE_NETWORK_MANAGER) && defined(BUILD_NETWORK) |
|
+ g_signal_connect_object (self->nm_client, "notify::nm-running" , |
|
+ G_CALLBACK (cc_wwan_device_nm_changed_cb), self, |
|
+ G_CONNECT_SWAPPED); |
|
+ |
|
+ g_signal_connect_object (self->nm_client, "device-added", |
|
+ G_CALLBACK (cc_wwan_device_nm_device_added_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+#endif |
|
+ |
|
+ g_signal_connect_object (self->mm_object, "notify::modem3gpp", |
|
+ G_CALLBACK (cc_wwan_device_3gpp_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ g_signal_connect_object (self->modem, "notify::signal-quality", |
|
+ G_CALLBACK (cc_wwan_device_signal_quality_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ cc_wwan_device_3gpp_changed_cb (self); |
|
+ g_signal_connect_object (self->modem, "notify::current-modes", |
|
+ G_CALLBACK (cc_wwan_device_mode_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ return self; |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_has_sim (CcWwanDevice *self) |
|
+{ |
|
+ MMModemStateFailedReason state_reason; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ |
|
+ state_reason = mm_modem_get_state_failed_reason (self->modem); |
|
+ |
|
+ if (state_reason == MM_MODEM_STATE_FAILED_REASON_SIM_MISSING) |
|
+ return FALSE; |
|
+ |
|
+ return TRUE; |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_device_get_lock: |
|
+ * @self: a #CcWwanDevice |
|
+ * |
|
+ * Get the active device lock that is required to |
|
+ * be unlocked for accessing device features. |
|
+ * |
|
+ * Returns: %TRUE if PIN enabled, %FALSE otherwise. |
|
+ */ |
|
+MMModemLock |
|
+cc_wwan_device_get_lock (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), MM_MODEM_LOCK_UNKNOWN); |
|
+ |
|
+ return mm_modem_get_unlock_required (self->modem); |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * cc_wwan_device_get_sim_lock: |
|
+ * @self: a #CcWwanDevice |
|
+ * |
|
+ * Get if SIM lock with PIN is enabled. SIM PIN |
|
+ * enabled doesn’t mean that SIM is locked. |
|
+ * See cc_wwan_device_get_lock(). |
|
+ * |
|
+ * Returns: %TRUE if PIN enabled, %FALSE otherwise. |
|
+ */ |
|
+gboolean |
|
+cc_wwan_device_get_sim_lock (CcWwanDevice *self) |
|
+{ |
|
+ gboolean sim_lock; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ |
|
+ sim_lock = self->locks & MM_MODEM_3GPP_FACILITY_SIM; |
|
+ |
|
+ return !!sim_lock; |
|
+} |
|
+ |
|
+guint |
|
+cc_wwan_device_get_unlock_retries (CcWwanDevice *self, |
|
+ MMModemLock lock) |
|
+{ |
|
+ MMUnlockRetries *retries; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), 0); |
|
+ |
|
+ retries = mm_modem_get_unlock_retries (self->modem); |
|
+ |
|
+ return mm_unlock_retries_get (retries, lock); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_pin_sent_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ MMSim *sim = (MMSim *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (!mm_sim_send_pin_finish (sim, result, &error)) |
|
+ { |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_device_send_pin (CcWwanDevice *self, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (MM_IS_SIM (self->sim)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ g_return_if_fail (pin && *pin); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ mm_sim_send_pin (self->sim, pin, cancellable, |
|
+ cc_wwan_device_pin_sent_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_send_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_puk_sent_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ MMSim *sim = (MMSim *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (!mm_sim_send_puk_finish (sim, result, &error)) |
|
+ { |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_device_send_puk (CcWwanDevice *self, |
|
+ const gchar *puk, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (MM_IS_SIM (self->sim)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ g_return_if_fail (puk && *puk); |
|
+ g_return_if_fail (pin && *pin); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ mm_sim_send_puk (self->sim, puk, pin, cancellable, |
|
+ cc_wwan_device_puk_sent_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_send_puk_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_enable_pin_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ MMSim *sim = (MMSim *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (!mm_sim_enable_pin_finish (sim, result, &error)) |
|
+ { |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_device_enable_pin (CcWwanDevice *self, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ g_return_if_fail (pin && *pin); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ mm_sim_enable_pin (self->sim, pin, cancellable, |
|
+ cc_wwan_device_enable_pin_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_enable_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_disable_pin_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ MMSim *sim = (MMSim *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (!mm_sim_disable_pin_finish (sim, result, &error)) |
|
+ { |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_device_disable_pin (CcWwanDevice *self, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ g_return_if_fail (pin && *pin); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ mm_sim_disable_pin (self->sim, pin, cancellable, |
|
+ cc_wwan_device_disable_pin_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_disable_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_change_pin_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ MMSim *sim = (MMSim *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (!mm_sim_change_pin_finish (sim, result, &error)) |
|
+ { |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_device_change_pin (CcWwanDevice *self, |
|
+ const gchar *old_pin, |
|
+ const gchar *new_pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ g_return_if_fail (old_pin && *old_pin); |
|
+ g_return_if_fail (new_pin && *new_pin); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ mm_sim_change_pin (self->sim, old_pin, new_pin, cancellable, |
|
+ cc_wwan_device_change_pin_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_change_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_network_mode_set_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ MMModem *modem = (MMModem *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (!mm_modem_set_current_modes_finish (modem, result, &error)) |
|
+ { |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_warning ("Error: %s", error->message); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_device_set_network_mode: |
|
+ * @self: a #CcWwanDevice |
|
+ * @allowed: The allowed #MMModemModes |
|
+ * @preferred: The preferred #MMModemMode |
|
+ * @cancellable: (nullable): a #GCancellable or %NULL |
|
+ * @callback: (nullable): a #GAsyncReadyCallback or %NULL |
|
+ * @user_data: (nullable): closure data for @callback |
|
+ * |
|
+ * Asynchronously set preferred network mode. |
|
+ * |
|
+ * Call @cc_wwan_device_set_current_mode_finish() |
|
+ * in @callback to get the result of operation. |
|
+ */ |
|
+void |
|
+cc_wwan_device_set_current_mode (CcWwanDevice *self, |
|
+ MMModemMode allowed, |
|
+ MMModemMode preferred, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ GPermission *permission; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ permission = polkit_permission_new_sync ("org.freedesktop.ModemManager1.Device.Control", |
|
+ NULL, cancellable, &error); |
|
+ if (permission) |
|
+ g_task_set_task_data (task, permission, g_object_unref); |
|
+ |
|
+ if (error) |
|
+ g_warning ("error: %s", error->message); |
|
+ |
|
+ if (error) |
|
+ { |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else if (!g_permission_get_allowed (permission)) |
|
+ { |
|
+ error = g_error_new (G_IO_ERROR, |
|
+ G_IO_ERROR_PERMISSION_DENIED, |
|
+ "Access Denied"); |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ mm_modem_set_current_modes (self->modem, allowed, preferred, |
|
+ cancellable, cc_wwan_device_network_mode_set_cb, |
|
+ g_steal_pointer (&task)); |
|
+ } |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_device_set_current_mode_finish: |
|
+ * @self: a #CcWwanDevice |
|
+ * @result: a #GAsyncResult |
|
+ * @error: a location for #GError or %NULL |
|
+ * |
|
+ * Get the status whether setting network mode |
|
+ * succeeded |
|
+ * |
|
+ * Returns: %TRUE if network mode was successfully set, |
|
+ * %FALSE otherwise. |
|
+ */ |
|
+gboolean |
|
+cc_wwan_device_set_current_mode_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_get_current_mode (CcWwanDevice *self, |
|
+ MMModemMode *allowed, |
|
+ MMModemMode *preferred) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ |
|
+ return mm_modem_get_current_modes (self->modem, allowed, preferred); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_is_auto_network (CcWwanDevice *self) |
|
+{ |
|
+ /* |
|
+ * XXX: ModemManager Doesn’t have a true API to check |
|
+ * if registration is automatic or manual. So Let’s |
|
+ * do some guess work. |
|
+ */ |
|
+ if (self->registration_state == CC_WWAN_REGISTRATION_STATE_DENIED) |
|
+ return FALSE; |
|
+ |
|
+ return !self->network_is_manual; |
|
+} |
|
+ |
|
+CcWwanState |
|
+cc_wwan_device_get_network_state (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), 0); |
|
+ |
|
+ return self->registration_state; |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_get_supported_modes (CcWwanDevice *self, |
|
+ MMModemMode *allowed, |
|
+ MMModemMode *preferred) |
|
+{ |
|
+ g_autofree MMModemModeCombination *modes = NULL; |
|
+ guint n_modes, i; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ |
|
+ if (!mm_modem_get_supported_modes (self->modem, &modes, &n_modes)) |
|
+ return FALSE; |
|
+ |
|
+ if (allowed) |
|
+ *allowed = 0; |
|
+ if (preferred) |
|
+ *preferred = 0; |
|
+ |
|
+ for (i = 0; i < n_modes; i++) |
|
+ { |
|
+ if (allowed) |
|
+ *allowed = *allowed | modes[i].allowed; |
|
+ if (preferred) |
|
+ *preferred = *preferred | modes[i].preferred; |
|
+ } |
|
+ |
|
+ return TRUE; |
|
+} |
|
+ |
|
+#define APPEND_MODE_TO_STRING(_str, _now, _preferred, _mode_str) do { \ |
|
+ if (_str->len > 0) \ |
|
+ g_string_append (_str, ", "); \ |
|
+ g_string_append (_str, _mode_str); \ |
|
+ if (_preferred == _now) \ |
|
+ g_string_append (_str, _(" (Preferred)")); \ |
|
+ } while (0) |
|
+ |
|
+gchar * |
|
+cc_wwan_device_get_string_from_mode (CcWwanDevice *self, |
|
+ MMModemMode allowed, |
|
+ MMModemMode preferred) |
|
+{ |
|
+ GString *str; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ g_return_val_if_fail (allowed != 0, NULL); |
|
+ |
|
+ str = g_string_sized_new (10); |
|
+ |
|
+ if (allowed & MM_MODEM_MODE_2G) |
|
+ APPEND_MODE_TO_STRING (str, MM_MODEM_MODE_2G, preferred, "2G"); |
|
+ if (allowed & MM_MODEM_MODE_3G) |
|
+ APPEND_MODE_TO_STRING (str, MM_MODEM_MODE_3G, preferred, "3G"); |
|
+ if (allowed & MM_MODEM_MODE_4G) |
|
+ APPEND_MODE_TO_STRING (str, MM_MODEM_MODE_4G, preferred, "4G"); |
|
+ |
|
+ if (allowed == MM_MODEM_MODE_2G || |
|
+ allowed == MM_MODEM_MODE_3G || |
|
+ allowed == MM_MODEM_MODE_4G) |
|
+ g_string_append (str, _(" Only")); |
|
+ |
|
+ if (str->len == 0) |
|
+ return g_string_free (str, TRUE); |
|
+ else |
|
+ return g_string_free (str, FALSE); |
|
+} |
|
+#undef APPEND_MODE_TO_STRING |
|
+ |
|
+static void |
|
+wwan_network_list_free (GList *network_list) |
|
+{ |
|
+ g_list_free_full (network_list, (GDestroyNotify)mm_modem_3gpp_network_free); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_scan_complete_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ MMModem3gpp *modem_3gpp = (MMModem3gpp *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ GList *network_list; |
|
+ |
|
+ network_list = mm_modem_3gpp_scan_finish (modem_3gpp, result, &error); |
|
+ |
|
+ if (error) |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ else |
|
+ g_task_return_pointer (task, network_list, (GDestroyNotify)wwan_network_list_free); |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_device_scan_networks (CcWwanDevice *self, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ mm_modem_3gpp_scan (self->modem_3gpp, cancellable, |
|
+ cc_wwan_device_scan_complete_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+GList * |
|
+cc_wwan_device_scan_networks_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_pointer (G_TASK (result), error); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_device_register_network_complete_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ CcWwanDevice *self; |
|
+ MMModem3gpp *modem_3gpp = (MMModem3gpp *)object; |
|
+ g_autoptr(GTask) task = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (!mm_modem_3gpp_register_finish (modem_3gpp, result, &error)) |
|
+ { |
|
+ self = g_task_get_source_object (G_TASK (task)); |
|
+ |
|
+ g_clear_error (&self->error); |
|
+ self->error = g_error_copy (error); |
|
+ g_warning ("Error: %s", error->message); |
|
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ERROR]); |
|
+ |
|
+ g_task_return_error (task, g_steal_pointer (&error)); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_task_return_boolean (task, TRUE); |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_device_register_network (CcWwanDevice *self, |
|
+ const gchar *network_id, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(GTask) task = NULL; |
|
+ |
|
+ g_return_if_fail (CC_IS_WWAN_DEVICE (self)); |
|
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
|
+ |
|
+ task = g_task_new (self, cancellable, callback, user_data); |
|
+ |
|
+ if (network_id && *network_id) |
|
+ self->network_is_manual = TRUE; |
|
+ else |
|
+ self->network_is_manual = FALSE; |
|
+ |
|
+ mm_modem_3gpp_register (self->modem_3gpp, network_id, cancellable, |
|
+ cc_wwan_device_register_network_complete_cb, |
|
+ g_steal_pointer (&task)); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_register_network_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), FALSE); |
|
+ g_return_val_if_fail (G_IS_TASK (result), FALSE); |
|
+ |
|
+ return g_task_propagate_boolean (G_TASK (result), error); |
|
+} |
|
+ |
|
+/** |
|
+ * cc_wwan_device_get_operator_name: |
|
+ * @self: a #CcWwanDevice |
|
+ * |
|
+ * Get the human readable network operator name |
|
+ * currently the device is connected to. |
|
+ * |
|
+ * Returns: (nullable): The operator name or %NULL |
|
+ */ |
|
+const gchar * |
|
+cc_wwan_device_get_operator_name (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ if (!self->modem_3gpp) |
|
+ return NULL; |
|
+ |
|
+ return mm_modem_3gpp_get_operator_name (self->modem_3gpp); |
|
+} |
|
+ |
|
+gchar * |
|
+cc_wwan_device_dup_own_numbers (CcWwanDevice *self) |
|
+{ |
|
+ const char *const *own_numbers; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ own_numbers = mm_modem_get_own_numbers (self->modem); |
|
+ |
|
+ if (!own_numbers) |
|
+ return NULL; |
|
+ |
|
+ return g_strjoinv ("\n", (char **)own_numbers); |
|
+} |
|
+ |
|
+gchar * |
|
+cc_wwan_device_dup_network_type_string (CcWwanDevice *self) |
|
+{ |
|
+ MMModemAccessTechnology type; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ type = mm_modem_get_access_technologies (self->modem); |
|
+ |
|
+ return mm_modem_access_technology_build_string_from_mask (type); |
|
+} |
|
+ |
|
+gchar * |
|
+cc_wwan_device_dup_signal_string (CcWwanDevice *self) |
|
+{ |
|
+ MMModemSignal *modem_signal; |
|
+ MMSignal *signal; |
|
+ GString *str; |
|
+ gdouble value; |
|
+ gboolean recent; |
|
+ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ modem_signal = mm_object_peek_modem_signal (self->mm_object); |
|
+ |
|
+ if (!modem_signal) |
|
+ return g_strdup_printf ("%d%%", mm_modem_get_signal_quality (self->modem, &recent)); |
|
+ |
|
+ str = g_string_new (""); |
|
+ |
|
+ /* Adapted from ModemManager mmcli-modem-signal.c */ |
|
+ signal = mm_modem_signal_peek_cdma (modem_signal); |
|
+ if (signal) |
|
+ { |
|
+ if ((value = mm_signal_get_rssi (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rssi: %.2g dBm ", value); |
|
+ if ((value = mm_signal_get_ecio (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "ecio: %.2g dBm ", value); |
|
+ } |
|
+ |
|
+ signal = mm_modem_signal_peek_evdo (modem_signal); |
|
+ if (signal) |
|
+ { |
|
+ if ((value = mm_signal_get_rssi (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rssi: %.2g dBm ", value); |
|
+ if ((value = mm_signal_get_ecio (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "ecio: %.2g dBm ", value); |
|
+ if ((value = mm_signal_get_sinr (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "sinr: %.2g dB ", value); |
|
+ if ((value = mm_signal_get_io (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "io: %.2g dBm ", value); |
|
+ } |
|
+ |
|
+ signal = mm_modem_signal_peek_gsm (modem_signal); |
|
+ if (signal) |
|
+ if ((value = mm_signal_get_rssi (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rssi: %.2g dBm ", value); |
|
+ |
|
+ signal = mm_modem_signal_peek_umts (modem_signal); |
|
+ if (signal) |
|
+ { |
|
+ if ((value = mm_signal_get_rssi (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rssi: %.2g dBm ", value); |
|
+ if ((value = mm_signal_get_rscp (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rscp: %.2g dBm ", value); |
|
+ if ((value = mm_signal_get_ecio (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "ecio: %.2g dBm ", value); |
|
+ } |
|
+ |
|
+ signal = mm_modem_signal_peek_lte (modem_signal); |
|
+ if (signal) |
|
+ { |
|
+ if ((value = mm_signal_get_rssi (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rssi: %.2g dBm ", value); |
|
+ if ((value = mm_signal_get_rsrq (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rsrq: %.2g dB ", value); |
|
+ if ((value = mm_signal_get_rsrp (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "rsrp: %.2g dBm ", value); |
|
+ if ((value = mm_signal_get_snr (signal)) != MM_SIGNAL_UNKNOWN) |
|
+ g_string_append_printf (str, "snr: %.2g dB ", value); |
|
+ } |
|
+ |
|
+ return g_string_free (str, FALSE); |
|
+} |
|
+ |
|
+const gchar * |
|
+cc_wwan_device_get_manufacturer (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ return mm_modem_get_manufacturer (self->modem); |
|
+} |
|
+ |
|
+const gchar * |
|
+cc_wwan_device_get_model (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ return mm_modem_get_model (self->modem); |
|
+} |
|
+ |
|
+const gchar * |
|
+cc_wwan_device_get_firmware_version (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ return mm_modem_get_revision (self->modem); |
|
+} |
|
+ |
|
+const gchar * |
|
+cc_wwan_device_get_identifier (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ return mm_modem_get_equipment_identifier (self->modem); |
|
+} |
|
+ |
|
+const gchar * |
|
+cc_wwan_device_get_simple_error (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ if (!self->error) |
|
+ return NULL; |
|
+ |
|
+ return cc_wwan_error_get_message (self->error); |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_is_nm_device (CcWwanDevice *self, |
|
+ GObject *nm_device) |
|
+{ |
|
+#if defined(HAVE_NETWORK_MANAGER) && defined(BUILD_NETWORK) |
|
+ g_return_val_if_fail (NM_IS_DEVICE (nm_device), FALSE); |
|
+ |
|
+ return g_str_equal (mm_modem_get_primary_port (self->modem), |
|
+ nm_device_get_iface (NM_DEVICE (nm_device))); |
|
+#else |
|
+ return FALSE; |
|
+#endif |
|
+} |
|
+ |
|
+const gchar * |
|
+cc_wwan_device_get_path (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), ""); |
|
+ |
|
+ return mm_object_get_path (self->mm_object); |
|
+} |
|
+ |
|
+CcWwanData * |
|
+cc_wwan_device_get_data (CcWwanDevice *self) |
|
+{ |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
+ |
|
+ return self->wwan_data; |
|
+} |
|
+ |
|
+gboolean |
|
+cc_wwan_device_pin_valid (const gchar *password, |
|
+ MMModemLock lock) |
|
+{ |
|
+ size_t len; |
|
+ |
|
+ g_return_val_if_fail (lock == MM_MODEM_LOCK_SIM_PIN || |
|
+ lock == MM_MODEM_LOCK_SIM_PIN2 || |
|
+ lock == MM_MODEM_LOCK_SIM_PUK || |
|
+ lock == MM_MODEM_LOCK_SIM_PUK2, FALSE); |
|
+ if (!password) |
|
+ return FALSE; |
|
+ |
|
+ len = strlen (password); |
|
+ |
|
+ if (len < 4 || len > 8) |
|
+ return FALSE; |
|
+ |
|
+ if (strspn (password, "0123456789") != len) |
|
+ return FALSE; |
|
+ |
|
+ /* |
|
+ * XXX: Can PUK code be something other than 8 digits? |
|
+ * 3GPP standard seems mum on this |
|
+ */ |
|
+ if (lock == MM_MODEM_LOCK_SIM_PUK || |
|
+ lock == MM_MODEM_LOCK_SIM_PUK2) |
|
+ if (len != 8) |
|
+ return FALSE; |
|
+ |
|
+ return TRUE; |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-device.h b/panels/wwan/cc-wwan-device.h |
|
new file mode 100644 |
|
index 000000000..e484bcf30 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-device.h |
|
@@ -0,0 +1,152 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-device.h |
|
+ * |
|
+ * Copyright 2019-2020 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <glib-object.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+#if defined(HAVE_NETWORK_MANAGER) && defined(BUILD_NETWORK) |
|
+# include "cc-wwan-data.h" |
|
+#endif |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+typedef enum |
|
+{ |
|
+ CC_WWAN_REGISTRATION_STATE_UNKNOWN, |
|
+ CC_WWAN_REGISTRATION_STATE_IDLE, |
|
+ CC_WWAN_REGISTRATION_STATE_REGISTERED, |
|
+ CC_WWAN_REGISTRATION_STATE_ROAMING, |
|
+ CC_WWAN_REGISTRATION_STATE_SEARCHING, |
|
+ CC_WWAN_REGISTRATION_STATE_DENIED |
|
+} CcWwanState; |
|
+ |
|
+typedef struct _CcWwanData CcWwanData; |
|
+ |
|
+#define CC_TYPE_WWAN_DEVICE (cc_wwan_device_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanDevice, cc_wwan_device, CC, WWAN_DEVICE, GObject) |
|
+ |
|
+CcWwanDevice *cc_wwan_device_new (MMObject *mm_object, |
|
+ GObject *nm_client); |
|
+gboolean cc_wwan_device_has_sim (CcWwanDevice *self); |
|
+MMModemLock cc_wwan_device_get_lock (CcWwanDevice *self); |
|
+gboolean cc_wwan_device_get_sim_lock (CcWwanDevice *self); |
|
+guint cc_wwan_device_get_unlock_retries (CcWwanDevice *self, |
|
+ MMModemLock lock); |
|
+void cc_wwan_device_enable_pin (CcWwanDevice *self, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_device_enable_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+void cc_wwan_device_disable_pin (CcWwanDevice *self, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_device_disable_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+void cc_wwan_device_send_pin (CcWwanDevice *self, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_device_send_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+void cc_wwan_device_send_puk (CcWwanDevice *self, |
|
+ const gchar *puk, |
|
+ const gchar *pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_device_send_puk_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+void cc_wwan_device_change_pin (CcWwanDevice *self, |
|
+ const gchar *old_pin, |
|
+ const gchar *new_pin, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_device_change_pin_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+const gchar *cc_wwan_device_get_operator_name (CcWwanDevice *self); |
|
+gchar *cc_wwan_device_dup_own_numbers (CcWwanDevice *self); |
|
+gchar *cc_wwan_device_dup_network_type_string (CcWwanDevice *self); |
|
+gchar *cc_wwan_device_dup_signal_string (CcWwanDevice *self); |
|
+const gchar *cc_wwan_device_get_manufacturer (CcWwanDevice *self); |
|
+const gchar *cc_wwan_device_get_model (CcWwanDevice *self); |
|
+const gchar *cc_wwan_device_get_firmware_version (CcWwanDevice *self); |
|
+const gchar *cc_wwan_device_get_identifier (CcWwanDevice *self); |
|
+gboolean cc_wwan_device_get_current_mode (CcWwanDevice *self, |
|
+ MMModemMode *allowed, |
|
+ MMModemMode *preferred); |
|
+gboolean cc_wwan_device_is_auto_network (CcWwanDevice *self); |
|
+CcWwanState cc_wwan_device_get_network_state (CcWwanDevice *self); |
|
+gboolean cc_wwan_device_get_supported_modes (CcWwanDevice *self, |
|
+ MMModemMode *allowed, |
|
+ MMModemMode *preferred); |
|
+void cc_wwan_device_set_current_mode (CcWwanDevice *self, |
|
+ MMModemMode allowed, |
|
+ MMModemMode preferred, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_device_set_current_mode_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+gchar *cc_wwan_device_get_string_from_mode (CcWwanDevice *self, |
|
+ MMModemMode allowed, |
|
+ MMModemMode preferred); |
|
+void cc_wwan_device_scan_networks (CcWwanDevice *self, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+GList *cc_wwan_device_scan_networks_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+void cc_wwan_device_register_network (CcWwanDevice *self, |
|
+ const gchar *network_id, |
|
+ GCancellable *cancellable, |
|
+ GAsyncReadyCallback callback, |
|
+ gpointer user_data); |
|
+gboolean cc_wwan_device_register_network_finish (CcWwanDevice *self, |
|
+ GAsyncResult *result, |
|
+ GError **error); |
|
+const gchar *cc_wwan_device_get_simple_error (CcWwanDevice *self); |
|
+GSList *cc_wwan_device_get_apn_list (CcWwanDevice *self); |
|
+gboolean cc_wwan_device_is_nm_device (CcWwanDevice *self, |
|
+ GObject *nm_device); |
|
+const gchar *cc_wwan_device_get_path (CcWwanDevice *self); |
|
+CcWwanData *cc_wwan_device_get_data (CcWwanDevice *self); |
|
+gboolean cc_wwan_device_pin_valid (const gchar *password, |
|
+ MMModemLock lock); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-errors-private.h b/panels/wwan/cc-wwan-errors-private.h |
|
new file mode 100644 |
|
index 000000000..761b82f35 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-errors-private.h |
|
@@ -0,0 +1,104 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-errors-private.h |
|
+ * |
|
+ * Copyright 2019 Purism SPC |
|
+ * |
|
+ * Modified from mm-error-helpers.c from ModemManager |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <glib/gi18n.h> |
|
+#include <glib-object.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+typedef struct { |
|
+ guint code; |
|
+ const gchar *message; |
|
+} ErrorTable; |
|
+ |
|
+ |
|
+static ErrorTable me_errors[] = { |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_PHONE_FAILURE, N_("Phone failure") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NO_CONNECTION, N_("No connection to phone") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_LINK_RESERVED, N_("Phone-adaptor link reserved") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED, N_("Operation not allowed") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, N_("Operation not supported") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_PH_SIM_PIN, N_("PH-SIM PIN required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_PH_FSIM_PIN, N_("PH-FSIM PIN required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_PH_FSIM_PUK, N_("PH-FSIM PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, N_("SIM not inserted") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN, N_("SIM PIN required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK, N_("SIM PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE, N_("SIM failure") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_BUSY, N_("SIM busy") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, N_("SIM wrong") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD, N_("Incorrect password") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN2, N_("SIM PIN2 required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK2, N_("SIM PUK2 required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FULL, N_("Memory full") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_INVALID_INDEX, N_("Invalid index") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NOT_FOUND, N_("Not found") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FAILURE, N_("Memory failure") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK, N_("No network service") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, N_("Network timeout") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED, N_("Network not allowed - emergency calls only") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_PIN, N_("Network personalization PIN required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_PUK, N_("Network personalization PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_SUBSET_PIN, N_("Network subset personalization PIN required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_SUBSET_PUK, N_("Network subset personalization PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SERVICE_PIN, N_("Service provider personalization PIN required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SERVICE_PUK, N_("Service provider personalization PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_CORP_PIN, N_("Corporate personalization PIN required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_CORP_PUK, N_("Corporate personalization PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN, N_("Unknown error") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_ILLEGAL_MS, N_("Illegal MS") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_ILLEGAL_ME, N_("Illegal ME") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_NOT_ALLOWED, N_("GPRS services not allowed") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_PLMN_NOT_ALLOWED, N_("PLMN not allowed") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_LOCATION_NOT_ALLOWED, N_("Location area not allowed") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_ROAMING_NOT_ALLOWED, N_("Roaming not allowed in this location area") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_NOT_SUPPORTED, N_("Service option not supported") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_NOT_SUBSCRIBED, N_("Requested service option not subscribed") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_OUT_OF_ORDER, N_("Service option temporarily out of order") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_UNKNOWN, N_("Unspecified GPRS error") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_PDP_AUTH_FAILURE, N_("PDP authentication failure") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_INVALID_MOBILE_CLASS, N_("Invalid mobile class") }, |
|
+}; |
|
+ |
|
+static inline const gchar * |
|
+cc_wwan_error_get_message (GError *error) |
|
+{ |
|
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
|
+ return _("Action Cancelled"); |
|
+ |
|
+ if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED)) |
|
+ return _("Access denied"); |
|
+ |
|
+ if (error->domain != MM_MOBILE_EQUIPMENT_ERROR) |
|
+ return error->message; |
|
+ |
|
+ for (guint i = 0; i < G_N_ELEMENTS (me_errors); i++) |
|
+ if (me_errors[i].code == error->code) |
|
+ return _(me_errors[i].message); |
|
+ |
|
+ return _("Unknown Error"); |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-mode-dialog.c b/panels/wwan/cc-wwan-mode-dialog.c |
|
new file mode 100644 |
|
index 000000000..e5917a41c |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-mode-dialog.c |
|
@@ -0,0 +1,327 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-mode-dialog.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-network-mode-dialog" |
|
+ |
|
+#include <config.h> |
|
+#include <glib/gi18n.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+#include "list-box-helper.h" |
|
+#include "cc-wwan-mode-dialog.h" |
|
+#include "cc-wwan-resources.h" |
|
+ |
|
+/** |
|
+ * @short_description: WWAN network type selection dialog |
|
+ */ |
|
+ |
|
+#define CC_TYPE_WWAN_MODE_ROW (cc_wwan_mode_row_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanModeRow, cc_wwan_mode_row, CC, WWAN_MODE_ROW, GtkListBoxRow) |
|
+ |
|
+struct _CcWwanModeDialog |
|
+{ |
|
+ GtkDialog parent_instance; |
|
+ |
|
+ CcWwanDevice *device; |
|
+ GtkListBox *network_mode_list; |
|
+ CcWwanModeRow *selected_row; |
|
+ |
|
+ MMModemMode preferred; |
|
+ MMModemMode allowed; |
|
+ MMModemMode new_allowed; |
|
+ MMModemMode new_preferred; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanModeDialog, cc_wwan_mode_dialog, GTK_TYPE_DIALOG) |
|
+ |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_DEVICE, |
|
+ N_PROPS |
|
+}; |
|
+ |
|
+static GParamSpec *properties[N_PROPS]; |
|
+ |
|
+struct _CcWwanModeRow |
|
+{ |
|
+ GtkListBoxRow parent_instance; |
|
+ GtkImage *ok_emblem; |
|
+ MMModemMode allowed; |
|
+ MMModemMode preferred; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanModeRow, cc_wwan_mode_row, GTK_TYPE_LIST_BOX_ROW) |
|
+ |
|
+static void |
|
+cc_wwan_mode_row_class_init (CcWwanModeRowClass *klass) |
|
+{ |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_row_init (CcWwanModeRow *row) |
|
+{ |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_changed_cb (CcWwanModeDialog *self, |
|
+ CcWwanModeRow *row) |
|
+{ |
|
+ g_assert (CC_IS_WWAN_MODE_DIALOG (self)); |
|
+ g_assert (CC_IS_WWAN_MODE_ROW (row)); |
|
+ |
|
+ if (row == self->selected_row) |
|
+ return; |
|
+ |
|
+ gtk_widget_show (GTK_WIDGET (row->ok_emblem)); |
|
+ |
|
+ if (self->selected_row) |
|
+ gtk_widget_hide (GTK_WIDGET (self->selected_row->ok_emblem)); |
|
+ |
|
+ self->selected_row = row; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_ok_clicked_cb (CcWwanModeDialog *self) |
|
+{ |
|
+ g_assert (CC_IS_WWAN_MODE_DIALOG (self)); |
|
+ |
|
+ if (self->selected_row) |
|
+ { |
|
+ cc_wwan_device_set_current_mode (self->device, |
|
+ self->selected_row->allowed, |
|
+ self->selected_row->preferred, |
|
+ NULL, NULL, NULL); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_return_if_reached (); |
|
+ } |
|
+ |
|
+ gtk_widget_hide (GTK_WIDGET (self)); |
|
+} |
|
+ |
|
+static GtkWidget * |
|
+cc_wwan_mode_dialog_row_new (CcWwanModeDialog *self, |
|
+ MMModemMode allowed, |
|
+ MMModemMode preferred) |
|
+{ |
|
+ CcWwanModeRow *row; |
|
+ GtkWidget *box, *label, *image; |
|
+ g_autofree gchar *mode = NULL; |
|
+ |
|
+ g_assert (CC_WWAN_MODE_DIALOG (self)); |
|
+ |
|
+ row = g_object_new (CC_TYPE_WWAN_MODE_ROW, NULL); |
|
+ row->allowed = allowed; |
|
+ row->preferred = preferred; |
|
+ |
|
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); |
|
+ gtk_widget_show (box); |
|
+ g_object_set (box, "margin", 18, NULL); |
|
+ gtk_container_add (GTK_CONTAINER (row), box); |
|
+ |
|
+ mode = cc_wwan_device_get_string_from_mode (self->device, allowed, preferred); |
|
+ label = gtk_label_new (mode); |
|
+ gtk_widget_show (label); |
|
+ gtk_widget_set_hexpand (label, TRUE); |
|
+ gtk_widget_set_halign (label, GTK_ALIGN_START); |
|
+ gtk_container_add (GTK_CONTAINER (box), label); |
|
+ |
|
+ /* image should be hidden by default */ |
|
+ image = gtk_image_new_from_icon_name ("emblem-ok-symbolic", GTK_ICON_SIZE_BUTTON); |
|
+ gtk_container_add (GTK_CONTAINER (box), image); |
|
+ row->ok_emblem = GTK_IMAGE (image); |
|
+ |
|
+ return GTK_WIDGET (row); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_update (CcWwanModeDialog *self) |
|
+{ |
|
+ MMModemMode allowed; |
|
+ MMModemMode modes[][2] = { |
|
+ {MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, MM_MODEM_MODE_4G}, |
|
+ {MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, 0}, |
|
+ {MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, MM_MODEM_MODE_4G}, |
|
+ {MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, 0}, |
|
+ {MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, MM_MODEM_MODE_3G}, |
|
+ {MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, 0}, |
|
+ {MM_MODEM_MODE_4G, 0}, |
|
+ {MM_MODEM_MODE_3G, 0}, |
|
+ {MM_MODEM_MODE_2G, 0}, |
|
+ }; |
|
+ size_t i; |
|
+ |
|
+ g_assert (CC_IS_WWAN_MODE_DIALOG (self)); |
|
+ |
|
+ if (!cc_wwan_device_get_supported_modes (self->device, &allowed, NULL)) |
|
+ { |
|
+ g_warning ("No modes supported by modem"); |
|
+ return; |
|
+ } |
|
+ |
|
+ for (i = 0; i < G_N_ELEMENTS (modes); i++) |
|
+ { |
|
+ GtkWidget *row; |
|
+ |
|
+ if ((modes[i][0] & allowed) != modes[i][0]) |
|
+ continue; |
|
+ |
|
+ if (modes[i][1] && !(modes[i][1] & allowed)) |
|
+ continue; |
|
+ |
|
+ row = cc_wwan_mode_dialog_row_new (self, modes[i][0], modes[i][1]); |
|
+ gtk_widget_show (row); |
|
+ gtk_container_add (GTK_CONTAINER (self->network_mode_list), row); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_set_property (GObject *object, |
|
+ guint prop_id, |
|
+ const GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanModeDialog *self = CC_WWAN_MODE_DIALOG (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_mode_dialog_constructed (GObject *object) |
|
+{ |
|
+ CcWwanModeDialog *self = CC_WWAN_MODE_DIALOG (object); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_mode_dialog_parent_class)->constructed (object); |
|
+ |
|
+ if(!cc_wwan_device_get_current_mode (self->device, &self->allowed, &self->preferred)) |
|
+ g_warning ("Can't get allowed and preferred wwan modes"); |
|
+ |
|
+ cc_wwan_mode_dialog_update (self); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_dispose (GObject *object) |
|
+{ |
|
+ CcWwanModeDialog *self = CC_WWAN_MODE_DIALOG (object); |
|
+ |
|
+ g_clear_object (&self->device); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_mode_dialog_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_update_mode (CcWwanModeRow *row, |
|
+ CcWwanModeDialog *self) |
|
+{ |
|
+ if (self->allowed == row->allowed && self->preferred == row->preferred) |
|
+ { |
|
+ self->selected_row = row; |
|
+ gtk_widget_show (GTK_WIDGET (row->ok_emblem)); |
|
+ } |
|
+ else |
|
+ gtk_widget_hide (GTK_WIDGET (row->ok_emblem)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_show (GtkWidget *widget) |
|
+{ |
|
+ CcWwanModeDialog *self = CC_WWAN_MODE_DIALOG (widget); |
|
+ |
|
+ if(!cc_wwan_device_get_current_mode (self->device, &self->allowed, &self->preferred)) |
|
+ { |
|
+ g_warning ("Can't get allowed and preferred wwan modes"); |
|
+ goto end; |
|
+ } |
|
+ |
|
+ gtk_container_foreach (GTK_CONTAINER (self->network_mode_list), |
|
+ (GtkCallback)cc_wwan_mode_dialog_update_mode, |
|
+ self); |
|
+ end: |
|
+ GTK_WIDGET_CLASS (cc_wwan_mode_dialog_parent_class)->show (widget); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_class_init (CcWwanModeDialogClass *klass) |
|
+{ |
|
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->set_property = cc_wwan_mode_dialog_set_property; |
|
+ object_class->constructed = cc_wwan_mode_dialog_constructed; |
|
+ object_class->dispose = cc_wwan_mode_dialog_dispose; |
|
+ |
|
+ widget_class->show = cc_wwan_mode_dialog_show; |
|
+ |
|
+ 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-mode-dialog.ui"); |
|
+ |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanModeDialog, network_mode_list); |
|
+ |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_mode_changed_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_mode_dialog_ok_clicked_cb); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_mode_dialog_init (CcWwanModeDialog *self) |
|
+{ |
|
+ gtk_widget_init_template (GTK_WIDGET (self)); |
|
+ |
|
+ gtk_list_box_set_header_func (self->network_mode_list, |
|
+ cc_list_box_update_header_func, |
|
+ NULL, NULL); |
|
+} |
|
+ |
|
+CcWwanModeDialog * |
|
+cc_wwan_mode_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device) |
|
+{ |
|
+ g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL); |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (device), NULL); |
|
+ |
|
+ return g_object_new (CC_TYPE_WWAN_MODE_DIALOG, |
|
+ "transient-for", parent_window, |
|
+ "use-header-bar", 1, |
|
+ "device", device, |
|
+ NULL); |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-mode-dialog.h b/panels/wwan/cc-wwan-mode-dialog.h |
|
new file mode 100644 |
|
index 000000000..2399f0b7b |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-mode-dialog.h |
|
@@ -0,0 +1,40 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-mode-dialog.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <handy.h> |
|
+#include <shell/cc-panel.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_TYPE_WWAN_MODE_DIALOG (cc_wwan_mode_dialog_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanModeDialog, cc_wwan_mode_dialog, CC, WWAN_MODE_DIALOG, GtkDialog) |
|
+ |
|
+CcWwanModeDialog *cc_wwan_mode_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-mode-dialog.ui b/panels/wwan/cc-wwan-mode-dialog.ui |
|
new file mode 100644 |
|
index 000000000..e0a924a39 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-mode-dialog.ui |
|
@@ -0,0 +1,57 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<interface> |
|
+ <template class="CcWwanModeDialog" parent="GtkDialog"> |
|
+ <property name="title" translatable="yes">Network Mode</property> |
|
+ <property name="default-height">480</property> |
|
+ <property name="default-width">360</property> |
|
+ <signal name="delete-event" handler="gtk_widget_hide_on_delete"/> |
|
+ |
|
+ <child internal-child="vbox"> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-start">12</property> |
|
+ <property name="margin-end">12</property> |
|
+ <property name="margin-top">18</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <child> |
|
+ <object class="GtkFrame"> |
|
+ <property name="visible">1</property> |
|
+ <child> |
|
+ <object class="GtkListBox" id="network_mode_list"> |
|
+ <property name="visible">1</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <signal name="row-activated" handler="cc_wwan_mode_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <child type="action"> |
|
+ <object class="GtkButton" id="button_cancel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Cancel</property> |
|
+ <signal name="clicked" handler="gtk_widget_hide" swapped="yes"/> |
|
+ </object> |
|
+ </child> |
|
+ <child type="action"> |
|
+ <object class="GtkButton" id="button_ok"> |
|
+ <property name="visible">1</property> |
|
+ <property name="can-default">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Set</property> |
|
+ <signal name="clicked" handler="cc_wwan_mode_dialog_ok_clicked_cb" swapped="yes"/> |
|
+ <style> |
|
+ <class name="suggested-action "/> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <action-widgets> |
|
+ <action-widget response="cancel">button_cancel</action-widget> |
|
+ <action-widget response="apply" default="true">button_ok</action-widget> |
|
+ </action-widgets> |
|
+ </template> |
|
+</interface> |
|
diff --git a/panels/wwan/cc-wwan-network-dialog.c b/panels/wwan/cc-wwan-network-dialog.c |
|
new file mode 100644 |
|
index 000000000..1c8883b88 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-network-dialog.c |
|
@@ -0,0 +1,443 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-network-dialog.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-network-dialog" |
|
+ |
|
+#include <config.h> |
|
+#include <glib/gi18n.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+#include "list-box-helper.h" |
|
+#include "cc-list-row.h" |
|
+#include "cc-wwan-errors-private.h" |
|
+#include "cc-wwan-network-dialog.h" |
|
+#include "cc-wwan-resources.h" |
|
+ |
|
+/** |
|
+ * @short_description: WWAN network operator selection dialog |
|
+ */ |
|
+ |
|
+#define CC_TYPE_WWAN_NETWORK_ROW (cc_wwan_network_row_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanNetworkRow, cc_wwan_network_row, CC, WWAN_NETWORK_ROW, GtkListBoxRow) |
|
+ |
|
+struct _CcWwanNetworkDialog |
|
+{ |
|
+ GtkDialog parent_instance; |
|
+ |
|
+ CcListRow *automatic_row; |
|
+ GtkButton *button_apply; |
|
+ GtkSpinner *loading_spinner; |
|
+ GtkBox *network_search_title; |
|
+ GtkLabel *notification_label; |
|
+ GtkRevealer *notification_revealer; |
|
+ GtkListBox *operator_list_box; |
|
+ GtkButton *refresh_button; |
|
+ |
|
+ CcWwanDevice *device; |
|
+ GList *operator_list; |
|
+ |
|
+ CcWwanNetworkRow *selected_row; |
|
+ |
|
+ GCancellable *search_cancellable; |
|
+ |
|
+ guint revealer_timeout_id; |
|
+ gboolean no_update_network; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanNetworkDialog, cc_wwan_network_dialog, GTK_TYPE_DIALOG) |
|
+ |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_DEVICE, |
|
+ N_PROPS |
|
+}; |
|
+ |
|
+static GParamSpec *properties[N_PROPS]; |
|
+ |
|
+struct _CcWwanNetworkRow |
|
+{ |
|
+ GtkListBoxRow parent_instance; |
|
+ GtkImage *ok_emblem; |
|
+ gchar *operator_code; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanNetworkRow, cc_wwan_network_row, GTK_TYPE_LIST_BOX_ROW) |
|
+ |
|
+static void |
|
+cc_wwan_network_row_finalize (GObject *object) |
|
+{ |
|
+ CcWwanNetworkRow *row = (CcWwanNetworkRow *)object; |
|
+ |
|
+ g_free (row->operator_code); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_network_row_parent_class)->finalize (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_row_class_init (CcWwanNetworkRowClass *klass) |
|
+{ |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->finalize = cc_wwan_network_row_finalize; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_row_init (CcWwanNetworkRow *row) |
|
+{ |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_on_notification_closed (CcWwanNetworkDialog *self, |
|
+ GtkWidget *button) |
|
+{ |
|
+ g_assert (CC_IS_WWAN_NETWORK_DIALOG (self)); |
|
+ |
|
+ gtk_revealer_set_reveal_child (GTK_REVEALER (self->notification_revealer), FALSE); |
|
+ |
|
+ if (self->revealer_timeout_id != 0) |
|
+ g_source_remove (self->revealer_timeout_id); |
|
+ |
|
+ self->revealer_timeout_id = 0; |
|
+} |
|
+ |
|
+static gboolean |
|
+cc_wwan_on_notification_timeout (gpointer user_data) |
|
+{ |
|
+ cc_wwan_on_notification_closed (user_data, NULL); |
|
+ |
|
+ return G_SOURCE_REMOVE; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_changed_cb (CcWwanNetworkDialog *self, |
|
+ CcWwanNetworkRow *row) |
|
+{ |
|
+ if (row == self->selected_row) |
|
+ return; |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->button_apply), TRUE); |
|
+ gtk_widget_show (GTK_WIDGET (row->ok_emblem)); |
|
+ |
|
+ if (self->selected_row) |
|
+ gtk_widget_hide (GTK_WIDGET (self->selected_row->ok_emblem)); |
|
+ |
|
+ self->selected_row = row; |
|
+} |
|
+ |
|
+/* |
|
+ * cc_wwan_network_dialog_row_new: |
|
+ * @self: a #CcWwanNetworkDialog |
|
+ * @operator_name: (transfer full): The long operator name |
|
+ * @operator_id: (transfer full): operator id |
|
+ */ |
|
+static CcWwanNetworkRow * |
|
+cc_wwan_network_dialog_row_new (CcWwanNetworkDialog *self, |
|
+ const gchar *operator_name, |
|
+ const gchar *operator_code) |
|
+{ |
|
+ CcWwanNetworkRow *row; |
|
+ GtkWidget *box, *label, *image; |
|
+ |
|
+ row = g_object_new (CC_TYPE_WWAN_NETWORK_ROW, NULL); |
|
+ |
|
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); |
|
+ gtk_widget_show (box); |
|
+ g_object_set (box, "margin", 18, NULL); |
|
+ gtk_container_add (GTK_CONTAINER (row), box); |
|
+ |
|
+ label = gtk_label_new (operator_name); |
|
+ gtk_widget_show (label); |
|
+ gtk_widget_set_hexpand (label, TRUE); |
|
+ gtk_widget_set_halign (label, GTK_ALIGN_START); |
|
+ gtk_container_add (GTK_CONTAINER (box), label); |
|
+ |
|
+ image = gtk_image_new_from_icon_name ("emblem-ok-symbolic", GTK_ICON_SIZE_BUTTON); |
|
+ row->ok_emblem = GTK_IMAGE (image); |
|
+ gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (row->ok_emblem)); |
|
+ |
|
+ row->operator_code = g_strdup (operator_code); |
|
+ |
|
+ return row; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_update_current_network (CcWwanNetworkDialog *self) |
|
+{ |
|
+ CcWwanNetworkRow *row; |
|
+ const gchar *operator_name; |
|
+ |
|
+ operator_name = cc_wwan_device_get_operator_name (self->device); |
|
+ |
|
+ if (!operator_name || operator_name[0] == '\0') |
|
+ return; |
|
+ |
|
+ gtk_container_foreach (GTK_CONTAINER (self->operator_list_box), |
|
+ (GtkCallback)gtk_widget_destroy, NULL); |
|
+ |
|
+ row = cc_wwan_network_dialog_row_new (self, operator_name, ""); |
|
+ self->selected_row = row; |
|
+ gtk_container_add (GTK_CONTAINER (self->operator_list_box), GTK_WIDGET (row)); |
|
+ gtk_widget_show_all (GTK_WIDGET (self->operator_list_box)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_update (CcWwanNetworkDialog *self) |
|
+{ |
|
+ CcWwanNetworkRow *row; |
|
+ GList *item; |
|
+ const gchar *operator_code, *operator_name; |
|
+ |
|
+ gtk_container_foreach (GTK_CONTAINER (self->operator_list_box), |
|
+ (GtkCallback)gtk_widget_destroy, NULL); |
|
+ |
|
+ for (item = self->operator_list; item; item = item->next) |
|
+ { |
|
+ operator_code = mm_modem_3gpp_network_get_operator_code (item->data); |
|
+ operator_name = mm_modem_3gpp_network_get_operator_long (item->data); |
|
+ |
|
+ row = cc_wwan_network_dialog_row_new (self, operator_name, operator_code); |
|
+ gtk_widget_show (GTK_WIDGET (row)); |
|
+ gtk_container_add (GTK_CONTAINER (self->operator_list_box), GTK_WIDGET (row)); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_scan_complete_cb (GObject *object, |
|
+ GAsyncResult *result, |
|
+ gpointer user_data) |
|
+{ |
|
+ g_autoptr(CcWwanNetworkDialog) self = user_data; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ if (self->operator_list) |
|
+ g_list_free_full (self->operator_list, (GDestroyNotify)mm_modem_3gpp_network_free); |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->refresh_button), TRUE); |
|
+ gtk_spinner_stop (self->loading_spinner); |
|
+ self->operator_list = cc_wwan_device_scan_networks_finish (self->device, result, &error); |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->operator_list_box), !error); |
|
+ |
|
+ if (!error) |
|
+ { |
|
+ cc_wwan_network_dialog_update (self); |
|
+ gtk_widget_show (GTK_WIDGET (self->operator_list_box)); |
|
+ } |
|
+ else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
|
+ { |
|
+ self->no_update_network = TRUE; |
|
+ gtk_widget_activate (GTK_WIDGET (self->automatic_row)); |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->operator_list_box), FALSE); |
|
+ |
|
+ gtk_label_set_label (self->notification_label, |
|
+ cc_wwan_error_get_message (error)); |
|
+ gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); |
|
+ self->revealer_timeout_id = g_timeout_add_seconds (5, cc_wwan_on_notification_timeout, self); |
|
+ |
|
+ gtk_widget_show (GTK_WIDGET (self->operator_list_box)); |
|
+ g_warning ("Error: scanning networks failed: %s", error->message); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_refresh_networks (CcWwanNetworkDialog *self) |
|
+{ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->refresh_button), FALSE); |
|
+ gtk_spinner_start (self->loading_spinner); |
|
+ cc_wwan_device_scan_networks (self->device, self->search_cancellable, |
|
+ (GAsyncReadyCallback)cc_wwan_network_scan_complete_cb, |
|
+ g_object_ref (self)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_apply_clicked_cb (CcWwanNetworkDialog *self) |
|
+{ |
|
+ gboolean is_auto; |
|
+ |
|
+ g_assert (CC_IS_WWAN_NETWORK_DIALOG (self)); |
|
+ |
|
+ is_auto = cc_list_row_get_active (self->automatic_row); |
|
+ |
|
+ if (is_auto) |
|
+ cc_wwan_device_register_network (self->device, "", NULL, NULL, NULL); |
|
+ else if (self->selected_row) |
|
+ cc_wwan_device_register_network (self->device, self->selected_row->operator_code, NULL, NULL, self); |
|
+ else |
|
+ g_warn_if_reached (); |
|
+ |
|
+ gtk_widget_hide (GTK_WIDGET (self)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_auto_network_changed_cb (CcWwanNetworkDialog *self, |
|
+ GParamSpec *pspec, |
|
+ CcListRow *auto_network_row) |
|
+{ |
|
+ gboolean is_auto; |
|
+ |
|
+ g_assert (CC_IS_WWAN_NETWORK_DIALOG (self)); |
|
+ g_assert (CC_IS_LIST_ROW (auto_network_row)); |
|
+ |
|
+ is_auto = cc_list_row_get_active (auto_network_row); |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->button_apply), is_auto); |
|
+ |
|
+ if (self->no_update_network) |
|
+ { |
|
+ self->no_update_network = FALSE; |
|
+ return; |
|
+ } |
|
+ |
|
+ self->selected_row = NULL; |
|
+ gtk_widget_set_visible (GTK_WIDGET (self->network_search_title), !is_auto); |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->operator_list_box), !is_auto); |
|
+ gtk_widget_hide (GTK_WIDGET (self->operator_list_box)); |
|
+ |
|
+ if (is_auto) |
|
+ { |
|
+ g_cancellable_cancel (self->search_cancellable); |
|
+ g_cancellable_reset (self->search_cancellable); |
|
+ } |
|
+ else |
|
+ { |
|
+ cc_wwan_network_dialog_refresh_networks (self); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_show (GtkWidget *widget) |
|
+{ |
|
+ CcWwanNetworkDialog *self = (CcWwanNetworkDialog *)widget; |
|
+ gboolean is_auto; |
|
+ |
|
+ is_auto = cc_wwan_device_is_auto_network (self->device); |
|
+ |
|
+ g_object_set (self->automatic_row, "active", is_auto, NULL); |
|
+ |
|
+ cc_wwan_network_dialog_update_current_network (self); |
|
+ |
|
+ GTK_WIDGET_CLASS (cc_wwan_network_dialog_parent_class)->show (widget); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_set_property (GObject *object, |
|
+ guint prop_id, |
|
+ const GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanNetworkDialog *self = (CcWwanNetworkDialog *)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_network_dialog_dispose (GObject *object) |
|
+{ |
|
+ CcWwanNetworkDialog *self = (CcWwanNetworkDialog *)object; |
|
+ |
|
+ if (self->revealer_timeout_id != 0) |
|
+ g_source_remove (self->revealer_timeout_id); |
|
+ |
|
+ self->revealer_timeout_id = 0; |
|
+ |
|
+ g_cancellable_cancel (self->search_cancellable); |
|
+ |
|
+ g_clear_object (&self->search_cancellable); |
|
+ g_clear_object (&self->device); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_network_dialog_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_class_init (CcWwanNetworkDialogClass *klass) |
|
+{ |
|
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->set_property = cc_wwan_network_dialog_set_property; |
|
+ object_class->dispose = cc_wwan_network_dialog_dispose; |
|
+ |
|
+ widget_class->show = cc_wwan_network_dialog_show; |
|
+ |
|
+ 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-network-dialog.ui"); |
|
+ |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, automatic_row); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, button_apply); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, loading_spinner); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, network_search_title); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, notification_label); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, notification_revealer); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, operator_list_box); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, refresh_button); |
|
+ |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_network_changed_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_on_notification_closed); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_auto_network_changed_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_network_dialog_refresh_networks); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_network_dialog_apply_clicked_cb); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_network_dialog_init (CcWwanNetworkDialog *self) |
|
+{ |
|
+ gtk_widget_init_template (GTK_WIDGET (self)); |
|
+ |
|
+ self->search_cancellable = g_cancellable_new (); |
|
+ |
|
+ gtk_list_box_set_header_func (self->operator_list_box, |
|
+ cc_list_box_update_header_func, |
|
+ NULL, NULL); |
|
+} |
|
+ |
|
+CcWwanNetworkDialog * |
|
+cc_wwan_network_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device) |
|
+{ |
|
+ g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL); |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (device), NULL); |
|
+ |
|
+ return g_object_new (CC_TYPE_WWAN_NETWORK_DIALOG, |
|
+ "transient-for", parent_window, |
|
+ "use-header-bar", 1, |
|
+ "device", device, |
|
+ NULL); |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-network-dialog.h b/panels/wwan/cc-wwan-network-dialog.h |
|
new file mode 100644 |
|
index 000000000..1818a0876 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-network-dialog.h |
|
@@ -0,0 +1,40 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-network-dialog.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <handy.h> |
|
+#include <shell/cc-panel.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_TYPE_WWAN_NETWORK_DIALOG (cc_wwan_network_dialog_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanNetworkDialog, cc_wwan_network_dialog, CC, WWAN_NETWORK_DIALOG, GtkDialog) |
|
+ |
|
+CcWwanNetworkDialog *cc_wwan_network_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-network-dialog.ui b/panels/wwan/cc-wwan-network-dialog.ui |
|
new file mode 100644 |
|
index 000000000..03223b333 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-network-dialog.ui |
|
@@ -0,0 +1,188 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<interface> |
|
+ <template class="CcWwanNetworkDialog" parent="GtkDialog"> |
|
+ <property name="title" translatable="yes">Network</property> |
|
+ <property name="default-height">480</property> |
|
+ <property name="default-width">360</property> |
|
+ <signal name="delete-event" handler="gtk_widget_hide_on_delete"/> |
|
+ |
|
+ <child internal-child="vbox"> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="border-width">0</property> |
|
+ <property name="width-request">340</property> |
|
+ <property name="height-request">360</property> |
|
+ <child> |
|
+ <object class="GtkOverlay"> |
|
+ <property name="visible">1</property> |
|
+ <child type="overlay"> |
|
+ <object class="GtkRevealer" id="notification_revealer"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">center</property> |
|
+ <property name="valign">start</property> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="spacing">12</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ <class name="app-notification" /> |
|
+ </style> |
|
+ <child> |
|
+ <object class="GtkLabel" id="notification_label"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="wrap-mode">word-char</property> |
|
+ <property name="use-markup">1</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkButton"> |
|
+ <property name="visible">1</property> |
|
+ <property name="relief">none</property> |
|
+ <signal name="clicked" handler="cc_wwan_on_notification_closed" swapped="yes" /> |
|
+ <child internal-child="accessible"> |
|
+ <object class="AtkObject"> |
|
+ <property name="accessible-name" translatable="yes">Close</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">window-close-symbolic</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-start">12</property> |
|
+ <property name="margin-end">12</property> |
|
+ <property name="margin-top">18</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <property name="orientation">vertical</property> |
|
+ |
|
+ <!-- Automatic Network Selection Switch --> |
|
+ <child> |
|
+ <object class="GtkListBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ </style> |
|
+ <child> |
|
+ <object class="CcListRow" id="automatic_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="show-switch">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="title" translatable="yes">_Automatic</property> |
|
+ <signal name="notify::active" handler="cc_wwan_auto_network_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Network Selection List Title and Spinner --> |
|
+ <child> |
|
+ <object class="GtkBox" id="network_search_title" > |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-bottom">9</property> |
|
+ <property name="spacing">6</property> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Choose Network</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold"/> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkSpinner" id="loading_spinner"> |
|
+ <property name="visible">1</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkButton" id="refresh_button"> |
|
+ <property name="visible">1</property> |
|
+ <signal name="clicked" handler="cc_wwan_network_dialog_refresh_networks" swapped="yes" /> |
|
+ <child internal-child="accessible"> |
|
+ <object class="AtkObject"> |
|
+ <property name="accessible-name" translatable="yes">Refresh Network Providers</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">view-refresh-symbolic</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="pack-type">end</property> |
|
+ </packing> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Network Selection List --> |
|
+ <child> |
|
+ <object class="GtkScrolledWindow"> |
|
+ <property name="visible">1</property> |
|
+ <property name="hscrollbar-policy">never</property> |
|
+ <property name="propagate-natural-height">1</property> |
|
+ <child> |
|
+ <object class="GtkListBox" id="operator_list_box"> |
|
+ <property name="visible">0</property> |
|
+ <property name="sensitive">0</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <signal name="row-activated" handler="cc_wwan_network_changed_cb" swapped="yes" /> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> <!-- ./internal-child --> |
|
+ |
|
+ <child type="action"> |
|
+ <object class="GtkButton" id="button_cancel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Cancel</property> |
|
+ <signal name="clicked" handler="gtk_widget_hide" swapped="yes"/> |
|
+ </object> |
|
+ </child> |
|
+ <child type="action"> |
|
+ <object class="GtkButton" id="button_apply"> |
|
+ <property name="visible">1</property> |
|
+ <property name="can-default">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Set</property> |
|
+ <signal name="clicked" handler="cc_wwan_network_dialog_apply_clicked_cb" swapped="yes"/> |
|
+ <style> |
|
+ <class name="suggested-action "/> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <action-widgets> |
|
+ <action-widget response="cancel">button_cancel</action-widget> |
|
+ <action-widget response="apply" default="true">button_apply</action-widget> |
|
+ </action-widgets> |
|
+ </template> |
|
+</interface> |
|
diff --git a/panels/wwan/cc-wwan-panel.c b/panels/wwan/cc-wwan-panel.c |
|
new file mode 100644 |
|
index 000000000..963c46900 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-panel.c |
|
@@ -0,0 +1,929 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-panel.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-panel" |
|
+ |
|
+#include <config.h> |
|
+#include <glib/gi18n.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+#include "cc-wwan-data.h" |
|
+#include "cc-wwan-device-page.h" |
|
+#include "cc-wwan-panel.h" |
|
+#include "cc-wwan-resources.h" |
|
+ |
|
+#include "shell/cc-application.h" |
|
+#include "shell/cc-debug.h" |
|
+#include "shell/cc-object-storage.h" |
|
+ |
|
+typedef enum { |
|
+ OPERATION_NULL, |
|
+ OPERATION_SHOW_DEVICE, |
|
+} CmdlineOperation; |
|
+ |
|
+struct _CcWwanPanel |
|
+{ |
|
+ CcPanel parent_instance; |
|
+ |
|
+ GtkListBox *data_select_listbox; |
|
+ GtkPopover *data_select_popover; |
|
+ GtkLabel *data_sim_label; |
|
+ GtkListBox *data_sim_select_listbox; |
|
+ GtkStack *devices_stack; |
|
+ GtkStackSwitcher *devices_switcher; |
|
+ GtkSwitch *enable_switch; |
|
+ GtkStack *main_stack; |
|
+ GtkRevealer *multi_device_revealer; |
|
+ GtkLabel *notification_label; |
|
+ GtkRevealer *notification_revealer; |
|
+ |
|
+ GDBusProxy *rfkill_proxy; |
|
+ MMManager *mm_manager; |
|
+ NMClient *nm_client; |
|
+ |
|
+ /* The default device that will be used for data */ |
|
+ CcWwanDevice *data_device; |
|
+ GListStore *devices; |
|
+ GListStore *data_devices; |
|
+ GCancellable *cancellable; |
|
+ |
|
+ CmdlineOperation arg_operation; |
|
+ char *arg_device; |
|
+ |
|
+ guint revealer_timeout_id; |
|
+}; |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_PARAMETERS |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanPanel, cc_wwan_panel, CC_TYPE_PANEL) |
|
+ |
|
+ |
|
+#define CC_TYPE_DATA_DEVICE_ROW (cc_data_device_row_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcDataDeviceRow, cc_data_device_row, CC, DATA_DEVICE_ROW, GtkListBoxRow) |
|
+ |
|
+struct _CcDataDeviceRow |
|
+{ |
|
+ GtkListBoxRow parent_instance; |
|
+ |
|
+ GtkImage *ok_emblem; |
|
+ CcWwanDevice *device; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcDataDeviceRow, cc_data_device_row, GTK_TYPE_LIST_BOX_ROW) |
|
+ |
|
+static void |
|
+cc_data_device_row_class_init (CcDataDeviceRowClass *klass) |
|
+{ |
|
+} |
|
+ |
|
+static void |
|
+cc_data_device_row_init (CcDataDeviceRow *row) |
|
+{ |
|
+} |
|
+ |
|
+static CmdlineOperation |
|
+cmdline_operation_from_string (const gchar *str) |
|
+{ |
|
+ if (g_strcmp0 (str, "show-device") == 0) |
|
+ return OPERATION_SHOW_DEVICE; |
|
+ |
|
+ g_warning ("Invalid additional argument %s", str); |
|
+ return OPERATION_NULL; |
|
+} |
|
+ |
|
+static void |
|
+reset_command_line_args (CcWwanPanel *self) |
|
+{ |
|
+ self->arg_operation = OPERATION_NULL; |
|
+ g_clear_pointer (&self->arg_device, g_free); |
|
+} |
|
+ |
|
+static gboolean |
|
+verify_argv (CcWwanPanel *self, |
|
+ const char **args) |
|
+{ |
|
+ switch (self->arg_operation) |
|
+ { |
|
+ case OPERATION_SHOW_DEVICE: |
|
+ if (self->arg_device == NULL) |
|
+ { |
|
+ g_warning ("Operation %s requires an object path", args[0]); |
|
+ return FALSE; |
|
+ } |
|
+ default: |
|
+ return TRUE; |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+handle_argv (CcWwanPanel *self) |
|
+{ |
|
+ if (self->arg_operation == OPERATION_SHOW_DEVICE && |
|
+ self->arg_operation) |
|
+ { |
|
+ g_autoptr(GList) pages = NULL; |
|
+ |
|
+ pages = gtk_container_get_children (GTK_CONTAINER (self->devices_stack)); |
|
+ |
|
+ for (GList *page = pages; page; page = page->next) |
|
+ { |
|
+ CcWwanDevice *device; |
|
+ |
|
+ device = cc_wwan_device_page_get_device (page->data); |
|
+ |
|
+ if (g_strcmp0 (cc_wwan_device_get_path (device), self->arg_device) == 0) |
|
+ { |
|
+ gtk_stack_set_visible_child (GTK_STACK (self->devices_stack), page->data); |
|
+ g_debug ("Opening device %s", self->arg_device); |
|
+ reset_command_line_args (self); |
|
+ return; |
|
+ } |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+static gboolean |
|
+wwan_panel_device_is_supported (GDBusObject *object) |
|
+{ |
|
+ MMObject *mm_object; |
|
+ MMModem *modem; |
|
+ MMModemCapability capability; |
|
+ |
|
+ g_assert (G_IS_DBUS_OBJECT (object)); |
|
+ |
|
+ mm_object = MM_OBJECT (object); |
|
+ modem = mm_object_get_modem (mm_object); |
|
+ capability = mm_modem_get_current_capabilities (modem); |
|
+ |
|
+ /* We Support only GSM/3G/LTE devices */ |
|
+ if (capability & (MM_MODEM_CAPABILITY_GSM_UMTS | |
|
+ MM_MODEM_CAPABILITY_LTE | |
|
+ MM_MODEM_CAPABILITY_LTE_ADVANCED)) |
|
+ return TRUE; |
|
+ |
|
+ return FALSE; |
|
+} |
|
+ |
|
+static gint |
|
+wwan_model_get_item_index (GListModel *model, |
|
+ gpointer item) |
|
+{ |
|
+ guint i, n_items; |
|
+ |
|
+ g_assert (G_IS_LIST_MODEL (model)); |
|
+ g_assert (G_IS_OBJECT (item)); |
|
+ |
|
+ n_items = g_list_model_get_n_items (model); |
|
+ |
|
+ for (i = 0; i < n_items; i++) |
|
+ { |
|
+ g_autoptr(GObject) object = NULL; |
|
+ |
|
+ object = g_list_model_get_item (model, i); |
|
+ |
|
+ if (object == item) |
|
+ return i; |
|
+ } |
|
+ |
|
+ return -1; |
|
+} |
|
+ |
|
+static CcWwanDevice * |
|
+wwan_model_get_item_from_mm_object (GListModel *model, |
|
+ MMObject *mm_object) |
|
+{ |
|
+ const gchar *modem_path, *device_path; |
|
+ guint i, n_items; |
|
+ |
|
+ n_items = g_list_model_get_n_items (model); |
|
+ modem_path = mm_object_get_path (mm_object); |
|
+ |
|
+ for (i = 0; i < n_items; i++) |
|
+ { |
|
+ g_autoptr(CcWwanDevice) device = NULL; |
|
+ |
|
+ device = g_list_model_get_item (model, i); |
|
+ device_path = cc_wwan_device_get_path (device); |
|
+ |
|
+ if (g_str_equal (modem_path, device_path)) |
|
+ return g_steal_pointer (&device); |
|
+ } |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+static CcDataDeviceRow * |
|
+cc_data_device_row_new (CcWwanDevice *device, |
|
+ CcWwanPanel *self) |
|
+{ |
|
+ CcDataDeviceRow *row; |
|
+ GtkWidget *box, *label, *image; |
|
+ g_autofree gchar *operator = NULL; |
|
+ gint index; |
|
+ |
|
+ row = g_object_new (CC_TYPE_DATA_DEVICE_ROW, NULL); |
|
+ row->device = device; |
|
+ |
|
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); |
|
+ gtk_widget_show (box); |
|
+ g_object_set (box, "margin", 12, NULL); |
|
+ gtk_container_add (GTK_CONTAINER (row), box); |
|
+ |
|
+ index = wwan_model_get_item_index (G_LIST_MODEL (self->devices), device); |
|
+ operator = g_strdup_printf ("SIM %d", index + 1); |
|
+ label = gtk_label_new (operator); |
|
+ gtk_widget_show (label); |
|
+ gtk_container_add (GTK_CONTAINER (box), label); |
|
+ |
|
+ image = gtk_image_new_from_icon_name ("emblem-ok-symbolic", GTK_ICON_SIZE_BUTTON); |
|
+ row->ok_emblem = GTK_IMAGE (image); |
|
+ gtk_container_add (GTK_CONTAINER (box), image); |
|
+ |
|
+ return row; |
|
+} |
|
+ |
|
+static void |
|
+wwan_notification_close_clicked_cb (CcWwanPanel *self) |
|
+{ |
|
+ gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); |
|
+ |
|
+ if (self->revealer_timeout_id != 0) |
|
+ g_source_remove (self->revealer_timeout_id); |
|
+ |
|
+ self->revealer_timeout_id = 0; |
|
+} |
|
+ |
|
+static void |
|
+wwan_data_selector_clicked_cb (CcWwanPanel *self) |
|
+{ |
|
+ if (gtk_widget_is_visible (GTK_WIDGET (self->data_select_popover))) |
|
+ gtk_popover_popdown (self->data_select_popover); |
|
+ else |
|
+ gtk_popover_popup (self->data_select_popover); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_update_data_selection (CcDataDeviceRow *row, |
|
+ CcWwanPanel *self) |
|
+{ |
|
+ if (self->data_device == row->device) |
|
+ { |
|
+ g_autofree gchar *str = NULL; |
|
+ gint i; |
|
+ |
|
+ i = wwan_model_get_item_index (G_LIST_MODEL (self->devices), row->device); |
|
+ g_assert (i >= 0); |
|
+ |
|
+ /* Human index starts from 1 */ |
|
+ str = g_strdup_printf ("SIM %d", i + 1); |
|
+ gtk_label_set_label (self->data_sim_label, str); |
|
+ |
|
+ gtk_widget_show (GTK_WIDGET (row->ok_emblem)); |
|
+ } |
|
+ else |
|
+ { |
|
+ gtk_widget_hide (GTK_WIDGET (row->ok_emblem)); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_data_item_activate_cb (CcWwanPanel *self, |
|
+ CcDataDeviceRow *row) |
|
+{ |
|
+ CcWwanData *data; |
|
+ |
|
+ gtk_popover_popdown (self->data_select_popover); |
|
+ |
|
+ if (row->device == self->data_device) |
|
+ return; |
|
+ |
|
+ /* Set lower priority for previously selected APN */ |
|
+ data = cc_wwan_device_get_data (self->data_device); |
|
+ cc_wwan_data_set_priority (data, CC_WWAN_APN_PRIORITY_LOW); |
|
+ cc_wwan_data_save_settings (data, NULL, NULL, NULL); |
|
+ |
|
+ /* Set high priority for currently selected APN */ |
|
+ data = cc_wwan_device_get_data (row->device); |
|
+ cc_wwan_data_set_priority (data, CC_WWAN_APN_PRIORITY_HIGH); |
|
+ cc_wwan_data_save_settings (data, NULL, NULL, NULL); |
|
+ |
|
+ self->data_device = row->device; |
|
+ gtk_container_foreach (GTK_CONTAINER (self->data_select_listbox), |
|
+ (GtkCallback) cc_wwan_panel_update_data_selection, self); |
|
+} |
|
+ |
|
+static void |
|
+wwan_on_airplane_off_clicked_cb (CcWwanPanel *self) |
|
+{ |
|
+ g_debug ("Airplane Mode Off clicked, disabling airplane mode"); |
|
+ g_dbus_proxy_call (self->rfkill_proxy, |
|
+ "org.freedesktop.DBus.Properties.Set", |
|
+ g_variant_new_parsed ("('org.gnome.SettingsDaemon.Rfkill'," |
|
+ "'AirplaneMode', %v)", |
|
+ g_variant_new_boolean (FALSE)), |
|
+ G_DBUS_CALL_FLAGS_NONE, |
|
+ -1, |
|
+ self->cancellable, |
|
+ NULL, |
|
+ NULL); |
|
+} |
|
+ |
|
+static gboolean |
|
+cc_wwan_panel_get_cached_dbus_property (GDBusProxy *proxy, |
|
+ const gchar *property) |
|
+{ |
|
+ g_autoptr(GVariant) result = NULL; |
|
+ |
|
+ g_assert (G_IS_DBUS_PROXY (proxy)); |
|
+ g_assert (property && *property); |
|
+ |
|
+ result = g_dbus_proxy_get_cached_property (proxy, property); |
|
+ g_assert (!result || g_variant_is_of_type (result, G_VARIANT_TYPE_BOOLEAN)); |
|
+ |
|
+ return result ? g_variant_get_boolean (result) : FALSE; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_update_view (CcWwanPanel *self) |
|
+{ |
|
+ gboolean has_airplane, is_airplane = FALSE, enabled = FALSE; |
|
+ |
|
+ has_airplane = cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "HasAirplaneMode"); |
|
+ has_airplane &= cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "ShouldShowAirplaneMode"); |
|
+ |
|
+ if (has_airplane) |
|
+ { |
|
+ is_airplane = cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "AirplaneMode"); |
|
+ is_airplane |= cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "HardwareAirplaneMode"); |
|
+ } |
|
+ |
|
+ if (self->nm_client) |
|
+ enabled = nm_client_wwan_get_enabled (self->nm_client); |
|
+ |
|
+ if (has_airplane && is_airplane) |
|
+ gtk_stack_set_visible_child_name (self->main_stack, "airplane-mode"); |
|
+ else if (enabled && g_list_model_get_n_items (G_LIST_MODEL (self->devices)) > 0) |
|
+ gtk_stack_set_visible_child_name (self->main_stack, "device-settings"); |
|
+ else |
|
+ gtk_stack_set_visible_child_name (self->main_stack, "no-wwan-devices"); |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->enable_switch), !is_airplane); |
|
+ |
|
+ if (enabled) |
|
+ gtk_revealer_set_reveal_child (self->multi_device_revealer, |
|
+ g_list_model_get_n_items (G_LIST_MODEL (self->devices)) > 1); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_on_notification_closed (CcWwanPanel *self, |
|
+ GtkWidget *button) |
|
+{ |
|
+ gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); |
|
+ |
|
+ if (self->revealer_timeout_id != 0) |
|
+ g_source_remove (self->revealer_timeout_id); |
|
+ |
|
+ self->revealer_timeout_id = 0; |
|
+} |
|
+ |
|
+static gboolean |
|
+cc_wwan_panel_on_notification_timeout (gpointer user_data) |
|
+{ |
|
+ cc_wwan_panel_on_notification_closed (user_data, NULL); |
|
+ |
|
+ return G_SOURCE_REMOVE; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_notification_changed_cb (CcWwanPanel *self) |
|
+{ |
|
+ const gchar *label; |
|
+ |
|
+ label = gtk_label_get_label (self->notification_label); |
|
+ |
|
+ if (label && *label) |
|
+ { |
|
+ gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); |
|
+ self->revealer_timeout_id = g_timeout_add_seconds (5, cc_wwan_panel_on_notification_timeout, self); |
|
+ } |
|
+ else |
|
+ { |
|
+ cc_wwan_panel_on_notification_closed (self, NULL); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_add_device (CcWwanPanel *self, |
|
+ CcWwanDevice *device) |
|
+{ |
|
+ CcWwanDevicePage *device_page; |
|
+ g_autofree gchar *operator_name = NULL; |
|
+ g_autofree gchar *stack_name = NULL; |
|
+ guint n_items; |
|
+ |
|
+ g_list_store_append (self->devices, device); |
|
+ |
|
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (self->devices)); |
|
+ operator_name = g_strdup_printf (_("SIM %d"), n_items); |
|
+ stack_name = g_strdup_printf ("sim-%d", n_items); |
|
+ |
|
+ device_page = cc_wwan_device_page_new (device, GTK_WIDGET (self->notification_label)); |
|
+ cc_wwan_device_page_set_sim_index (device_page, n_items); |
|
+ gtk_stack_add_titled (self->devices_stack, |
|
+ GTK_WIDGET (device_page), stack_name, operator_name); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_update_page_title (CcWwanDevicePage *device_page, |
|
+ CcWwanPanel *self) |
|
+{ |
|
+ g_autofree gchar *title = NULL; |
|
+ g_autofree gchar *name = NULL; |
|
+ CcWwanDevice *device; |
|
+ GtkWidget *parent; |
|
+ gint index; |
|
+ |
|
+ device = cc_wwan_device_page_get_device (device_page); |
|
+ |
|
+ parent = gtk_widget_get_parent (GTK_WIDGET (device_page)); |
|
+ index = wwan_model_get_item_index (G_LIST_MODEL (self->devices), device); |
|
+ |
|
+ if (index == -1) |
|
+ g_return_if_reached (); |
|
+ |
|
+ /* index starts with 0, but we need human readable index to be 1+ */ |
|
+ cc_wwan_device_page_set_sim_index (device_page, index + 1); |
|
+ title = g_strdup_printf (_("SIM %d"), index + 1); |
|
+ name = g_strdup_printf ("sim-%d", index + 1); |
|
+ gtk_container_child_set (GTK_CONTAINER (parent), |
|
+ GTK_WIDGET (device_page), |
|
+ "title", title, |
|
+ "name", name, |
|
+ NULL); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_remove_mm_object (CcWwanPanel *self, |
|
+ MMObject *mm_object) |
|
+{ |
|
+ g_autoptr(CcWwanDevice) device = NULL; |
|
+ GtkWidget *device_page; |
|
+ g_autofree gchar *stack_name = NULL; |
|
+ guint n_items; |
|
+ gint index; |
|
+ |
|
+ device = wwan_model_get_item_from_mm_object (G_LIST_MODEL (self->devices), mm_object); |
|
+ |
|
+ if (!device) |
|
+ return; |
|
+ |
|
+ index = wwan_model_get_item_index (G_LIST_MODEL (self->data_devices), device); |
|
+ if (index != -1) |
|
+ g_list_store_remove (self->data_devices, index); |
|
+ |
|
+ index = wwan_model_get_item_index (G_LIST_MODEL (self->devices), device); |
|
+ if (index == -1) |
|
+ return; |
|
+ |
|
+ g_list_store_remove (self->devices, index); |
|
+ stack_name = g_strdup_printf ("sim-%d", index + 1); |
|
+ device_page = gtk_stack_get_child_by_name (self->devices_stack, stack_name); |
|
+ gtk_container_remove (GTK_CONTAINER (self->devices_stack), device_page); |
|
+ |
|
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (self->data_devices)); |
|
+ g_list_model_items_changed (G_LIST_MODEL (self->data_devices), 0, n_items, n_items); |
|
+ gtk_container_foreach (GTK_CONTAINER (self->devices_stack), |
|
+ (GtkCallback)cc_wwan_panel_update_page_title, |
|
+ self); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_update_data_connections (CcWwanPanel *self) |
|
+{ |
|
+ CcWwanData *device_data, *active_data = NULL; |
|
+ guint n_items; |
|
+ gint i; |
|
+ |
|
+ /* |
|
+ * We can’t predict the order in which the data of device is enabled. |
|
+ * But we have to keep data store in the same order as device store. |
|
+ * So let’s remove every data device and re-add. |
|
+ */ |
|
+ g_list_store_remove_all (self->data_devices); |
|
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (self->devices)); |
|
+ |
|
+ for (i = 0; i < n_items; i++) |
|
+ { |
|
+ g_autoptr(CcWwanDevice) device = NULL; |
|
+ |
|
+ device = g_list_model_get_item (G_LIST_MODEL (self->devices), i); |
|
+ device_data = cc_wwan_device_get_data (device); |
|
+ |
|
+ if (!device_data) |
|
+ continue; |
|
+ |
|
+ if ((!active_data || |
|
+ cc_wwan_data_get_priority (device_data) > cc_wwan_data_get_priority (active_data)) && |
|
+ cc_wwan_data_get_enabled (device_data)) |
|
+ { |
|
+ active_data = device_data; |
|
+ self->data_device = device; |
|
+ } |
|
+ |
|
+ if (cc_wwan_data_get_enabled (device_data)) |
|
+ g_list_store_append (self->data_devices, device); |
|
+ } |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->data_sim_select_listbox), |
|
+ g_list_model_get_n_items (G_LIST_MODEL (self->data_devices)) > 1); |
|
+ if (active_data) |
|
+ gtk_container_foreach (GTK_CONTAINER (self->data_select_listbox), |
|
+ (GtkCallback)cc_wwan_panel_update_data_selection, self); |
|
+ else |
|
+ gtk_label_set_label (self->data_sim_label, ""); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_update_devices (CcWwanPanel *self) |
|
+{ |
|
+ GList *devices, *iter; |
|
+ |
|
+ devices = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->mm_manager)); |
|
+ |
|
+ for (iter = devices; iter; iter = iter->next) |
|
+ { |
|
+ MMObject *mm_object = iter->data; |
|
+ CcWwanDevice *device; |
|
+ |
|
+ if(!wwan_panel_device_is_supported (iter->data)) |
|
+ continue; |
|
+ |
|
+ device = cc_wwan_device_new (mm_object, G_OBJECT (self->nm_client)); |
|
+ cc_wwan_panel_add_device (self, device); |
|
+ g_signal_connect_object (device, "notify::has-data", |
|
+ G_CALLBACK (cc_wwan_panel_update_data_connections), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ if (cc_wwan_device_get_data (device)) |
|
+ g_list_store_append (self->data_devices, device); |
|
+ } |
|
+ |
|
+ cc_wwan_panel_update_data_connections (self); |
|
+ handle_argv (self); |
|
+} |
|
+ |
|
+static void |
|
+wwan_panel_device_added_cb (CcWwanPanel *self, |
|
+ GDBusObject *object) |
|
+{ |
|
+ CcWwanDevice *device; |
|
+ |
|
+ if(!wwan_panel_device_is_supported (object)) |
|
+ return; |
|
+ |
|
+ device = cc_wwan_device_new (MM_OBJECT (object), G_OBJECT (self->nm_client)); |
|
+ cc_wwan_panel_add_device (self, device); |
|
+ g_signal_connect_object (device, "notify::has-data", |
|
+ G_CALLBACK (cc_wwan_panel_update_data_connections), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ cc_wwan_panel_update_view (self); |
|
+ handle_argv (self); |
|
+} |
|
+ |
|
+static void |
|
+wwan_panel_device_removed_cb (CcWwanPanel *self, |
|
+ GDBusObject *object) |
|
+{ |
|
+ if (!wwan_panel_device_is_supported (object)) |
|
+ return; |
|
+ |
|
+ cc_wwan_panel_remove_mm_object (self, MM_OBJECT (object)); |
|
+ |
|
+ gtk_revealer_set_reveal_child (self->multi_device_revealer, |
|
+ g_list_model_get_n_items (G_LIST_MODEL (self->devices)) > 1); |
|
+} |
|
+ |
|
+static GPtrArray * |
|
+variant_av_to_string_array (GVariant *array) |
|
+{ |
|
+ GVariant *v; |
|
+ GPtrArray *strv; |
|
+ GVariantIter iter; |
|
+ gsize count; |
|
+ |
|
+ count = g_variant_iter_init (&iter, array); |
|
+ strv = g_ptr_array_sized_new (count + 1); |
|
+ |
|
+ while (g_variant_iter_next (&iter, "v", &v)) |
|
+ { |
|
+ g_ptr_array_add (strv, (gpointer)g_variant_get_string (v, NULL)); |
|
+ g_variant_unref (v); |
|
+ } |
|
+ g_ptr_array_add (strv, NULL); /* NULL-terminate the strv data array */ |
|
+ |
|
+ return strv; |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_set_property (GObject *object, |
|
+ guint property_id, |
|
+ const GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanPanel *self = CC_WWAN_PANEL (object); |
|
+ |
|
+ switch (property_id) |
|
+ { |
|
+ case PROP_PARAMETERS: |
|
+ { |
|
+ GVariant *parameters; |
|
+ |
|
+ reset_command_line_args (self); |
|
+ |
|
+ parameters = g_value_get_variant (value); |
|
+ if (parameters) |
|
+ { |
|
+ g_autoptr(GPtrArray) array = NULL; |
|
+ const gchar **args; |
|
+ |
|
+ array = variant_av_to_string_array (parameters); |
|
+ args = (const gchar **) array->pdata; |
|
+ |
|
+ g_debug ("Invoked with operation %s", args[0]); |
|
+ |
|
+ if (args[0]) |
|
+ self->arg_operation = cmdline_operation_from_string (args[0]); |
|
+ if (args[0] && args[1]) |
|
+ self->arg_device = g_strdup (args[1]); |
|
+ |
|
+ if (!verify_argv (self, (const char **) args)) |
|
+ { |
|
+ reset_command_line_args (self); |
|
+ return; |
|
+ } |
|
+ g_debug ("Calling handle_argv() after setting property"); |
|
+ handle_argv (self); |
|
+ } |
|
+ break; |
|
+ } |
|
+ default: |
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_constructed (GObject *object) |
|
+{ |
|
+ CcWwanPanel *self = (CcWwanPanel *)object; |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_panel_parent_class)->constructed (object); |
|
+ |
|
+ cc_shell_embed_widget_in_header (cc_panel_get_shell (CC_PANEL (self)), |
|
+ GTK_WIDGET (self->enable_switch), GTK_POS_RIGHT); |
|
+ |
|
+ if (self->nm_client) |
|
+ { |
|
+ g_object_bind_property (self->nm_client, "wwan-enabled", |
|
+ self->enable_switch, "active", |
|
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_dispose (GObject *object) |
|
+{ |
|
+ CcWwanPanel *self = (CcWwanPanel *)object; |
|
+ |
|
+ if (self->revealer_timeout_id != 0) |
|
+ g_source_remove (self->revealer_timeout_id); |
|
+ |
|
+ self->revealer_timeout_id = 0; |
|
+ |
|
+ g_cancellable_cancel (self->cancellable); |
|
+ |
|
+ g_clear_object (&self->devices); |
|
+ g_clear_object (&self->data_devices); |
|
+ g_clear_object (&self->mm_manager); |
|
+ g_clear_object (&self->nm_client); |
|
+ g_clear_object (&self->cancellable); |
|
+ g_clear_object (&self->rfkill_proxy); |
|
+ g_clear_pointer (&self->arg_device, g_free); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_panel_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_class_init (CcWwanPanelClass *klass) |
|
+{ |
|
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->set_property = cc_wwan_panel_set_property; |
|
+ object_class->constructed = cc_wwan_panel_constructed; |
|
+ object_class->dispose = cc_wwan_panel_dispose; |
|
+ |
|
+ g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters"); |
|
+ |
|
+ gtk_widget_class_set_template_from_resource (widget_class, |
|
+ "/org/gnome/control-center/wwan/cc-wwan-panel.ui"); |
|
+ |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, data_select_listbox); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, data_select_popover); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, data_sim_label); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, data_sim_select_listbox); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, devices_stack); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, devices_switcher); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, enable_switch); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, main_stack); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, multi_device_revealer); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, notification_label); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, notification_revealer); |
|
+ |
|
+ gtk_widget_class_bind_template_callback (widget_class, wwan_on_airplane_off_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, wwan_notification_close_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, wwan_data_selector_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_data_item_activate_cb); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_panel_init (CcWwanPanel *self) |
|
+{ |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ g_resources_register (cc_wwan_get_resource ()); |
|
+ |
|
+ gtk_widget_init_template (GTK_WIDGET (self)); |
|
+ |
|
+ self->cancellable = g_cancellable_new (); |
|
+ self->devices = g_list_store_new (CC_TYPE_WWAN_DEVICE); |
|
+ self->data_devices = g_list_store_new (CC_TYPE_WWAN_DEVICE); |
|
+ gtk_list_box_bind_model (GTK_LIST_BOX (self->data_select_listbox), |
|
+ G_LIST_MODEL (self->data_devices), |
|
+ (GtkListBoxCreateWidgetFunc) cc_data_device_row_new, |
|
+ self, NULL); |
|
+ |
|
+ g_signal_connect_object (self->notification_label, "notify::label", |
|
+ G_CALLBACK (cc_wwan_panel_notification_changed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ if (cc_object_storage_has_object (CC_OBJECT_NMCLIENT)) |
|
+ { |
|
+ self->nm_client = cc_object_storage_get_object (CC_OBJECT_NMCLIENT); |
|
+ g_signal_connect_object (self->nm_client, |
|
+ "notify::wwan-enabled", |
|
+ G_CALLBACK (cc_wwan_panel_update_view), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ } |
|
+ else |
|
+ { |
|
+ g_warn_if_reached (); |
|
+ } |
|
+ |
|
+ if (cc_object_storage_has_object ("CcObjectStorage::mm-manager")) |
|
+ { |
|
+ self->mm_manager = cc_object_storage_get_object ("CcObjectStorage::mm-manager"); |
|
+ |
|
+ g_signal_connect_object (self->mm_manager, "object-added", |
|
+ G_CALLBACK (wwan_panel_device_added_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ g_signal_connect_object (self->mm_manager, "object-removed", |
|
+ G_CALLBACK (wwan_panel_device_removed_cb), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ cc_wwan_panel_update_devices (self); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_warn_if_reached (); |
|
+ } |
|
+ |
|
+ /* Acquire Airplane Mode proxy */ |
|
+ self->rfkill_proxy = cc_object_storage_create_dbus_proxy_sync (G_BUS_TYPE_SESSION, |
|
+ G_DBUS_PROXY_FLAGS_NONE, |
|
+ "org.gnome.SettingsDaemon.Rfkill", |
|
+ "/org/gnome/SettingsDaemon/Rfkill", |
|
+ "org.gnome.SettingsDaemon.Rfkill", |
|
+ self->cancellable, |
|
+ &error); |
|
+ |
|
+ if (error) |
|
+ { |
|
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
|
+ g_printerr ("Error creating rfkill proxy: %s\n", error->message); |
|
+ } |
|
+ else |
|
+ { |
|
+ g_signal_connect_object (self->rfkill_proxy, |
|
+ "g-properties-changed", |
|
+ G_CALLBACK (cc_wwan_panel_update_view), |
|
+ self, G_CONNECT_SWAPPED); |
|
+ |
|
+ cc_wwan_panel_update_view (self); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+wwan_update_panel_visibility (MMManager *mm_manager) |
|
+{ |
|
+ CcApplication *application; |
|
+ GList *devices; |
|
+ gboolean has_wwan; |
|
+ |
|
+ g_assert (MM_IS_MANAGER (mm_manager)); |
|
+ |
|
+ CC_TRACE_MSG ("Updating WWAN panel visibility"); |
|
+ |
|
+ has_wwan = FALSE; |
|
+ devices = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (mm_manager)); |
|
+ |
|
+ for (GList *item = devices; item != NULL; item = item->next) |
|
+ { |
|
+ if(wwan_panel_device_is_supported (item->data)) |
|
+ { |
|
+ has_wwan = TRUE; |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ /* Set the new visibility */ |
|
+ application = CC_APPLICATION (g_application_get_default ()); |
|
+ cc_shell_model_set_panel_visibility (cc_application_get_model (application), |
|
+ "wwan", |
|
+ has_wwan ? CC_PANEL_VISIBLE : CC_PANEL_VISIBLE_IN_SEARCH); |
|
+ |
|
+ g_debug ("WWAN panel visible: %s", has_wwan ? "yes" : "no"); |
|
+ |
|
+ g_list_free_full (devices, (GDestroyNotify)g_object_unref); |
|
+} |
|
+ |
|
+void |
|
+cc_wwan_panel_static_init_func (void) |
|
+{ |
|
+ g_autoptr(GDBusConnection) system_bus = NULL; |
|
+ g_autoptr(MMManager) mm_manager = NULL; |
|
+ g_autoptr(GError) error = NULL; |
|
+ |
|
+ /* |
|
+ * There could be other modems that are only handled by rfkill, |
|
+ * and not available via ModemManager. But as this panel |
|
+ * makes use of ModemManager APIs, we only care devices |
|
+ * supported by ModemManager. |
|
+ */ |
|
+ system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); |
|
+ if (system_bus == NULL) |
|
+ g_warning ("Error connecting to system D-Bus: %s", error->message); |
|
+ else |
|
+ mm_manager = mm_manager_new_sync (system_bus, |
|
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, |
|
+ NULL, &error); |
|
+ |
|
+ if (mm_manager == NULL) |
|
+ { |
|
+ CcApplication *application; |
|
+ |
|
+ g_warning ("Error connecting to ModemManager: %s", error->message); |
|
+ |
|
+ application = CC_APPLICATION (g_application_get_default ()); |
|
+ cc_shell_model_set_panel_visibility (cc_application_get_model (application), |
|
+ "wwan", FALSE); |
|
+ return; |
|
+ } |
|
+ else |
|
+ { |
|
+ cc_object_storage_add_object ("CcObjectStorage::mm-manager", mm_manager); |
|
+ } |
|
+ |
|
+ g_debug ("Monitoring ModemManager for WWAN devices"); |
|
+ |
|
+ g_signal_connect (mm_manager, "object-added", G_CALLBACK (wwan_update_panel_visibility), NULL); |
|
+ g_signal_connect (mm_manager, "object-removed", G_CALLBACK (wwan_update_panel_visibility), NULL); |
|
+ |
|
+ wwan_update_panel_visibility (mm_manager); |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-panel.h b/panels/wwan/cc-wwan-panel.h |
|
new file mode 100644 |
|
index 000000000..57d2dae26 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-panel.h |
|
@@ -0,0 +1,36 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-panel.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <shell/cc-panel.h> |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_TYPE_WWAN_PANEL (cc_wwan_panel_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanPanel, cc_wwan_panel, CC, WWAN_PANEL, CcPanel) |
|
+ |
|
+void cc_wwan_panel_static_init_func (void); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-panel.ui b/panels/wwan/cc-wwan-panel.ui |
|
new file mode 100644 |
|
index 000000000..5258c42c3 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-panel.ui |
|
@@ -0,0 +1,336 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<interface> |
|
+ <template class="CcWwanPanel" parent="CcPanel"> |
|
+ <property name="visible">1</property> |
|
+ |
|
+ <child> |
|
+ <object class="GtkOverlay"> |
|
+ <property name="visible">1</property> |
|
+ |
|
+ <!-- Notification Revealer --> |
|
+ <child type="overlay"> |
|
+ <object class="GtkRevealer" id="notification_revealer"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">center</property> |
|
+ <property name="valign">start</property> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="spacing">12</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ <class name="app-notification" /> |
|
+ </style> |
|
+ <child> |
|
+ <object class="GtkLabel" id="notification_label"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="wrap-mode">word</property> |
|
+ <property name="use-markup">1</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkButton"> |
|
+ <property name="visible">1</property> |
|
+ <property name="relief">none</property> |
|
+ <signal name="clicked" handler="wwan_notification_close_clicked_cb" swapped="yes" /> |
|
+ <child internal-child="accessible"> |
|
+ <object class="AtkObject"> |
|
+ <property name="accessible-name" translatable="yes">Close</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">window-close-symbolic</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <child> |
|
+ <object class="GtkScrolledWindow"> |
|
+ <property name="visible">1</property> |
|
+ <property name="hscrollbar-policy">never</property> |
|
+ <property name="min-content-height">500</property> |
|
+ <child> |
|
+ <object class="HdyClamp"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-top">0</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <property name="margin-start">18</property> |
|
+ <property name="margin-end">18</property> |
|
+ |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="hexpand">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ <child> |
|
+ <object class="GtkStack" id="main_stack"> |
|
+ <property name="visible">1</property> |
|
+ <property name="homogeneous">0</property> |
|
+ <property name="transition-type">crossfade</property> |
|
+ |
|
+ <!-- "No WWAN Adapter" page --> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="expand">1</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="orientation">vertical</property> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">network-cellular-offline-symbolic</property> |
|
+ <property name="pixel-size">192</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="label" translatable="yes">No WWAN Adapter Found</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold" /> |
|
+ <attribute name="scale" value="1.2" /> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="label" translatable="yes">Make sure you have a Wireless Wan/Cellular device</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">no-wwan-devices</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- "Airplane Mode" page --> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="expand">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ <property name="valign">center</property> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">airplane-mode-symbolic</property> |
|
+ <property name="pixel-size">192</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="label" translatable="yes">Airplane Mode On</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold" /> |
|
+ <attribute name="scale" value="1.2" /> |
|
+ </attributes> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="label" translatable="yes">Wireless Wan is disabled when airplane mode is on</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkButton"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">center</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="margin-top">24</property> |
|
+ <property name="label" translatable="yes">_Turn off Airplane Mode</property> |
|
+ <signal name="clicked" handler="wwan_on_airplane_off_clicked_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">airplane-mode</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ |
|
+ <child> |
|
+ <object class="GtkRevealer" id="multi_device_revealer"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-top">18</property> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ |
|
+ <!-- Data SIM selector --> |
|
+ <child> |
|
+ <object class="GtkListBox" id="data_sim_select_listbox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <signal name="row-activated" handler="wwan_data_selector_clicked_cb" swapped="yes" /> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ </style> |
|
+ <child> |
|
+ <object class="GtkGrid"> |
|
+ <property name="visible">1</property> |
|
+ <property name="border-width">9</property> |
|
+ <property name="margin-start">9</property> |
|
+ <property name="margin-end">9</property> |
|
+ <property name="column-spacing">12</property> |
|
+ |
|
+ <!-- Title --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="hexpand">1</property> |
|
+ <property name="label" translatable="yes">Data Connection</property> |
|
+ <property name="xalign">0.0</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">0</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- SubTitle --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="hexpand">1</property> |
|
+ <property name="label" translatable="yes">SIM card used for internet</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <attributes> |
|
+ <attribute name="scale" value="0.88" /> |
|
+ </attributes> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">1</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Network Name --> |
|
+ <child> |
|
+ <object class="GtkLabel" id="data_sim_label"> |
|
+ <property name="visible">1</property> |
|
+ <property name="valign">center</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">0</property> |
|
+ <property name="height">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Popover Arrow --> |
|
+ <child> |
|
+ <object class="GtkImage" id="popover_arrow"> |
|
+ <property name="visible">1</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="icon-name">pan-down-symbolic</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">2</property> |
|
+ <property name="top-attach">0</property> |
|
+ <property name="height">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Device (SIM) Name --> |
|
+ <child> |
|
+ <object class="GtkStackSwitcher" id="devices_switcher"> |
|
+ <property name="stack">devices_stack</property> |
|
+ <property name="visible">1</property> |
|
+ <property name="hexpand">1</property> |
|
+ <property name="halign">center</property> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <!-- Device (SIM) settings page --> |
|
+ <child> |
|
+ <object class="GtkStack" id="devices_stack"> |
|
+ <property name="visible">1</property> |
|
+ <property name="homogeneous">0</property> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">device-settings</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> <!-- ./GtkStack main_stack --> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> <!-- ./HdyClamp --> |
|
+ </child> |
|
+ </object> <!-- ./GtkScrolledWindow --> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </template> |
|
+ |
|
+ <object class="GtkPopover" id="data_select_popover"> |
|
+ <property name="position">bottom</property> |
|
+ <property name="relative-to">popover_arrow</property> |
|
+ <child> |
|
+ <object class="GtkListBox" id="data_select_listbox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <signal name="row-activated" handler="cc_wwan_data_item_activate_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ |
|
+ <!-- Cellular panel on/off switch --> |
|
+ <object class="GtkSwitch" id="enable_switch"> |
|
+ <property name="visible">1</property> |
|
+ <child internal-child="accessible"> |
|
+ <object class="AtkObject"> |
|
+ <property name="accessible-name" translatable="yes">Enable Mobile Network</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+</interface> |
|
diff --git a/panels/wwan/cc-wwan-sim-lock-dialog.c b/panels/wwan/cc-wwan-sim-lock-dialog.c |
|
new file mode 100644 |
|
index 000000000..14adbf415 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-sim-lock-dialog.c |
|
@@ -0,0 +1,310 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-network-dialog.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-sim-lock-dialog" |
|
+ |
|
+#include <config.h> |
|
+#include <glib/gi18n.h> |
|
+#include <libmm-glib.h> |
|
+ |
|
+#include "list-box-helper.h" |
|
+#include "cc-list-row.h" |
|
+#include "cc-wwan-sim-lock-dialog.h" |
|
+#include "cc-wwan-resources.h" |
|
+ |
|
+/** |
|
+ * @short_description: Dialog to manage SIM Locks like PIN |
|
+ */ |
|
+ |
|
+#define PIN_MINIMUM_LENGTH 4 |
|
+#define PIN_MAXIMUM_LENGTH 8 |
|
+ |
|
+struct _CcWwanSimLockDialog |
|
+{ |
|
+ GtkDialog parent_instance; |
|
+ |
|
+ CcWwanDevice *device; |
|
+ |
|
+ GtkButton *apply_button; |
|
+ GtkStack *button_stack; |
|
+ GtkGrid *lock_change_grid; |
|
+ CcListRow *lock_row; |
|
+ GtkEntry *new_pin_entry; |
|
+ GtkButton *next_button; |
|
+ GtkEntry *pin_confirm_entry; |
|
+ GtkEntry *pin_entry; |
|
+ GtkStack *pin_settings_stack; |
|
+}; |
|
+ |
|
+G_DEFINE_TYPE (CcWwanSimLockDialog, cc_wwan_sim_lock_dialog, GTK_TYPE_DIALOG) |
|
+ |
|
+ |
|
+enum { |
|
+ PROP_0, |
|
+ PROP_DEVICE, |
|
+ N_PROPS |
|
+}; |
|
+ |
|
+static GParamSpec *properties[N_PROPS]; |
|
+ |
|
+static void |
|
+cc_wwan_sim_lock_changed_cb (CcWwanSimLockDialog *self) |
|
+{ |
|
+ gboolean row_enabled, lock_enabled; |
|
+ |
|
+ lock_enabled = cc_wwan_device_get_sim_lock (self->device); |
|
+ row_enabled = cc_list_row_get_active (self->lock_row); |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->next_button), lock_enabled != row_enabled); |
|
+ gtk_widget_set_visible (GTK_WIDGET (self->lock_change_grid), row_enabled && lock_enabled); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_pin_next_clicked_cb (CcWwanSimLockDialog *self) |
|
+{ |
|
+ gtk_stack_set_visible_child_name (self->pin_settings_stack, "pin-entry"); |
|
+ gtk_entry_set_text (self->pin_entry, ""); |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->apply_button), FALSE); |
|
+ gtk_stack_set_visible_child (self->button_stack, |
|
+ GTK_WIDGET (self->apply_button)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_pin_apply_clicked_cb (CcWwanSimLockDialog *self) |
|
+{ |
|
+ const gchar *pin, *new_pin; |
|
+ gboolean row_enabled, lock_enabled; |
|
+ |
|
+ gtk_widget_hide (GTK_WIDGET (self)); |
|
+ |
|
+ lock_enabled = cc_wwan_device_get_sim_lock (self->device); |
|
+ row_enabled = cc_list_row_get_active (self->lock_row); |
|
+ pin = gtk_entry_get_text (self->pin_entry); |
|
+ new_pin = gtk_entry_get_text (self->new_pin_entry); |
|
+ |
|
+ if (lock_enabled != row_enabled) |
|
+ { |
|
+ if (row_enabled) |
|
+ cc_wwan_device_enable_pin (self->device, pin, NULL, NULL, NULL); |
|
+ else |
|
+ cc_wwan_device_disable_pin (self->device, pin, NULL, NULL, NULL); |
|
+ |
|
+ return; |
|
+ } |
|
+ |
|
+ cc_wwan_device_change_pin (self->device, pin, new_pin, NULL, NULL, NULL); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_pin_entry_text_inserted_cb (CcWwanSimLockDialog *self, |
|
+ gchar *new_text, |
|
+ gint new_text_length, |
|
+ gpointer position, |
|
+ GtkEditable *editable) |
|
+{ |
|
+ size_t digit_end; |
|
+ size_t len; |
|
+ |
|
+ if (!new_text || !*new_text) |
|
+ return; |
|
+ |
|
+ if (new_text_length == 1 && g_ascii_isdigit (*new_text)) |
|
+ return; |
|
+ |
|
+ if (new_text_length == -1) |
|
+ len = strlen (new_text); |
|
+ else |
|
+ len = new_text_length; |
|
+ |
|
+ if (len == 1 && g_ascii_isdigit (*new_text)) |
|
+ return; |
|
+ |
|
+ digit_end = strspn (new_text, "1234567890"); |
|
+ |
|
+ /* The maximum length possible for PIN is 8 */ |
|
+ if (len <= 8 && digit_end == len) |
|
+ return; |
|
+ |
|
+ g_signal_stop_emission_by_name (editable, "insert-text"); |
|
+ gtk_widget_error_bell (GTK_WIDGET (editable)); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_pin_entry_changed_cb (CcWwanSimLockDialog *self) |
|
+{ |
|
+ const gchar *new_pin, *confirm_pin; |
|
+ |
|
+ new_pin = gtk_entry_get_text (self->new_pin_entry); |
|
+ confirm_pin = gtk_entry_get_text (self->pin_confirm_entry); |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->next_button), FALSE); |
|
+ |
|
+ /* A PIN should have a minimum length of 4 */ |
|
+ if (!new_pin || !confirm_pin || strlen (new_pin) < 4) |
|
+ return; |
|
+ |
|
+ if (g_str_equal (new_pin, confirm_pin)) |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->next_button), TRUE); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+cc_wwan_pin_entered_cb (CcWwanSimLockDialog *self) |
|
+{ |
|
+ const gchar *pin; |
|
+ gsize len; |
|
+ gboolean enable_apply; |
|
+ |
|
+ pin = gtk_entry_get_text (self->pin_entry); |
|
+ |
|
+ if (!pin || !*pin) |
|
+ { |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->apply_button), FALSE); |
|
+ return; |
|
+ } |
|
+ |
|
+ len = strlen (pin); |
|
+ enable_apply = len >= PIN_MINIMUM_LENGTH && len <= PIN_MAXIMUM_LENGTH; |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->apply_button), enable_apply); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_sim_lock_dialog_set_property (GObject *object, |
|
+ guint prop_id, |
|
+ const GValue *value, |
|
+ GParamSpec *pspec) |
|
+{ |
|
+ CcWwanSimLockDialog *self = (CcWwanSimLockDialog *)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_sim_lock_dialog_show (GtkWidget *widget) |
|
+{ |
|
+ CcWwanSimLockDialog *self = (CcWwanSimLockDialog *)widget; |
|
+ gboolean lock_enabled; |
|
+ |
|
+ gtk_entry_set_text (self->pin_entry, ""); |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->next_button), FALSE); |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->apply_button), FALSE); |
|
+ |
|
+ lock_enabled = cc_wwan_device_get_sim_lock (self->device); |
|
+ g_object_set (self->lock_row, "active", lock_enabled, NULL); |
|
+ gtk_widget_set_visible (GTK_WIDGET (self->lock_change_grid), lock_enabled); |
|
+ |
|
+ gtk_widget_set_sensitive (GTK_WIDGET (self->next_button), FALSE); |
|
+ gtk_stack_set_visible_child (self->button_stack, |
|
+ GTK_WIDGET (self->next_button)); |
|
+ gtk_button_set_label (self->apply_button, _("_Set")); |
|
+ |
|
+ gtk_stack_set_visible_child_name (self->pin_settings_stack, "pin-settings"); |
|
+ |
|
+ gtk_entry_set_text (self->pin_entry, ""); |
|
+ gtk_entry_set_text (self->new_pin_entry, ""); |
|
+ gtk_entry_set_text (self->pin_confirm_entry, ""); |
|
+ |
|
+ GTK_WIDGET_CLASS (cc_wwan_sim_lock_dialog_parent_class)->show (widget); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_sim_lock_dialog_dispose (GObject *object) |
|
+{ |
|
+ CcWwanSimLockDialog *self = (CcWwanSimLockDialog *)object; |
|
+ |
|
+ g_clear_object (&self->device); |
|
+ |
|
+ G_OBJECT_CLASS (cc_wwan_sim_lock_dialog_parent_class)->dispose (object); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_sim_lock_dialog_class_init (CcWwanSimLockDialogClass *klass) |
|
+{ |
|
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
|
+ |
|
+ object_class->set_property = cc_wwan_sim_lock_dialog_set_property; |
|
+ object_class->dispose = cc_wwan_sim_lock_dialog_dispose; |
|
+ |
|
+ widget_class->show = cc_wwan_sim_lock_dialog_show; |
|
+ |
|
+ 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-sim-lock-dialog.ui"); |
|
+ |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, apply_button); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, button_stack); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, lock_change_grid); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, lock_row); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, new_pin_entry); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, next_button); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, pin_confirm_entry); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, pin_entry); |
|
+ gtk_widget_class_bind_template_child (widget_class, CcWwanSimLockDialog, pin_settings_stack); |
|
+ |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_sim_lock_changed_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_pin_next_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_pin_apply_clicked_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_pin_entry_text_inserted_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_pin_entry_changed_cb); |
|
+ gtk_widget_class_bind_template_callback (widget_class, cc_wwan_pin_entered_cb); |
|
+} |
|
+ |
|
+static void |
|
+cc_wwan_sim_lock_dialog_init (CcWwanSimLockDialog *self) |
|
+{ |
|
+ gtk_widget_init_template (GTK_WIDGET (self)); |
|
+} |
|
+ |
|
+CcWwanSimLockDialog * |
|
+cc_wwan_sim_lock_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device) |
|
+{ |
|
+ g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL); |
|
+ g_return_val_if_fail (CC_IS_WWAN_DEVICE (device), NULL); |
|
+ |
|
+ return g_object_new (CC_TYPE_WWAN_SIM_LOCK_DIALOG, |
|
+ "transient-for", parent_window, |
|
+ "use-header-bar", 1, |
|
+ "device", device, |
|
+ NULL); |
|
+} |
|
diff --git a/panels/wwan/cc-wwan-sim-lock-dialog.h b/panels/wwan/cc-wwan-sim-lock-dialog.h |
|
new file mode 100644 |
|
index 000000000..b6d1d5a9e |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-sim-lock-dialog.h |
|
@@ -0,0 +1,40 @@ |
|
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
+/* cc-wwan-sim-lock-dialog.h |
|
+ * |
|
+ * 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 |
|
+ */ |
|
+ |
|
+#pragma once |
|
+ |
|
+#include <handy.h> |
|
+#include <shell/cc-panel.h> |
|
+ |
|
+#include "cc-wwan-device.h" |
|
+ |
|
+G_BEGIN_DECLS |
|
+ |
|
+#define CC_TYPE_WWAN_SIM_LOCK_DIALOG (cc_wwan_sim_lock_dialog_get_type()) |
|
+G_DECLARE_FINAL_TYPE (CcWwanSimLockDialog, cc_wwan_sim_lock_dialog, CC, WWAN_SIM_LOCK_DIALOG, GtkDialog) |
|
+ |
|
+CcWwanSimLockDialog *cc_wwan_sim_lock_dialog_new (GtkWindow *parent_window, |
|
+ CcWwanDevice *device); |
|
+ |
|
+G_END_DECLS |
|
diff --git a/panels/wwan/cc-wwan-sim-lock-dialog.ui b/panels/wwan/cc-wwan-sim-lock-dialog.ui |
|
new file mode 100644 |
|
index 000000000..48a946be4 |
|
--- /dev/null |
|
+++ b/panels/wwan/cc-wwan-sim-lock-dialog.ui |
|
@@ -0,0 +1,306 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<interface> |
|
+ <template class="CcWwanSimLockDialog" parent="GtkDialog"> |
|
+ <property name="default-height">480</property> |
|
+ <property name="default-width">360</property> |
|
+ <signal name="delete-event" handler="gtk_widget_hide_on_delete"/> |
|
+ |
|
+ <child type="titlebar"> |
|
+ <object class="GtkHeaderBar"> |
|
+ <property name="visible">1</property> |
|
+ <property name="title" translatable="yes">SIM Lock</property> |
|
+ <child> |
|
+ <object class="GtkStack" id="button_stack"> |
|
+ <property name="visible">1</property> |
|
+ |
|
+ <!-- Next Buttoon --> |
|
+ <child> |
|
+ <object class="GtkButton" id="next_button"> |
|
+ <property name="visible">1</property> |
|
+ <property name="sensitive">0</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Next</property> |
|
+ <signal name="clicked" handler="cc_wwan_pin_next_clicked_cb" swapped="yes" /> |
|
+ <style> |
|
+ <class name="suggested-action" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">next</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Apply button --> |
|
+ <child> |
|
+ <object class="GtkButton" id="apply_button"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <signal name="clicked" handler="cc_wwan_pin_apply_clicked_cb" swapped="yes" /> |
|
+ <style> |
|
+ <class name="suggested-action" /> |
|
+ </style> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">apply</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ <packing> |
|
+ <property name="pack-type">end</property> |
|
+ </packing> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <child internal-child="vbox"> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="border-width">0</property> |
|
+ <property name="width-request">340</property> |
|
+ <property name="height-request">360</property> |
|
+ |
|
+ <child> |
|
+ <object class="HdyClamp"> |
|
+ <property name="visible">1</property> |
|
+ <property name="margin-top">32</property> |
|
+ <property name="margin-bottom">32</property> |
|
+ <property name="margin-start">18</property> |
|
+ <property name="margin-end">18</property> |
|
+ <child> |
|
+ <object class="GtkOverlay"> |
|
+ <property name="visible">1</property> |
|
+ <child type="overlay"> |
|
+ <object class="GtkRevealer" id="notification_revealer"> |
|
+ <property name="visible">1</property> |
|
+ <property name="halign">center</property> |
|
+ <property name="valign">start</property> |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="spacing">12</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ <class name="app-notification" /> |
|
+ </style> |
|
+ <child> |
|
+ <object class="GtkLabel" id="notification_label"> |
|
+ <property name="visible">1</property> |
|
+ <property name="wrap">1</property> |
|
+ <property name="wrap-mode">word-char</property> |
|
+ <property name="use-markup">1</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkButton"> |
|
+ <property name="visible">1</property> |
|
+ <property name="relief">none</property> |
|
+ <!-- <signal name="clicked" handler="cc_wwan_on_notification_closed" object="CcWwanSimLockDialog" swapped="yes" /> --> |
|
+ <child internal-child="accessible"> |
|
+ <object class="AtkObject"> |
|
+ <property name="accessible-name" translatable="yes">Close</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="icon-name">window-close-symbolic</property> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <child> |
|
+ <object class="GtkStack" id="pin_settings_stack"> |
|
+ <property name="visible">1</property> |
|
+ <property name="transition-type">slide-left</property> |
|
+ |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ |
|
+ <!-- SIM Lock Switch --> |
|
+ <child> |
|
+ <object class="GtkListBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="selection-mode">none</property> |
|
+ <property name="margin-bottom">18</property> |
|
+ <style> |
|
+ <class name="frame" /> |
|
+ </style> |
|
+ <child> |
|
+ <object class="CcListRow" id="lock_row"> |
|
+ <property name="visible">1</property> |
|
+ <property name="show-switch">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="title" translatable="yes">_Lock SIM with PIN</property> |
|
+ <signal name="notify::active" handler="cc_wwan_sim_lock_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ <child> |
|
+ <object class="GtkGrid" id="lock_change_grid"> |
|
+ <property name="visible">0</property> |
|
+ <property name="row-spacing">18</property> |
|
+ <property name="column-spacing">12</property> |
|
+ |
|
+ <!-- SIM Lock Change Title --> |
|
+ <child> |
|
+ <object class="GtkLabel" id="lock_change_title"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Change PIN</property> |
|
+ <property name="margin-bottom">9</property> |
|
+ <property name="xalign">0.0</property> |
|
+ <attributes> |
|
+ <attribute name="weight" value="bold"/> |
|
+ </attributes> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">0</property> |
|
+ <property name="width">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- PIN Entry --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label">New PIN</property> |
|
+ <property name="halign">end</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">1</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkEntry" id="new_pin_entry"> |
|
+ <property name="visible">1</property> |
|
+ <property name="visibility">0</property> |
|
+ <property name="input-purpose">password</property> |
|
+ <property name="input-hints">no-emoji</property> |
|
+ <property name="max-length">8</property> |
|
+ <property name="max-width-chars">32</property> |
|
+ <signal name="notify::text" handler="cc_wwan_pin_entry_changed_cb" swapped="yes" /> |
|
+ <signal name="insert-text" handler="cc_wwan_pin_entry_text_inserted_cb" swapped="yes" /> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">1</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <!-- Confirm PIN Entry --> |
|
+ <child> |
|
+ <object class="GtkLabel"> |
|
+ <property name="visible">1</property> |
|
+ <property name="label">Confirm</property> |
|
+ <property name="halign">end</property> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">0</property> |
|
+ <property name="top-attach">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkEntry" id="pin_confirm_entry"> |
|
+ <property name="visible">1</property> |
|
+ <property name="visibility">0</property> |
|
+ <property name="input-purpose">password</property> |
|
+ <property name="input-hints">no-emoji</property> |
|
+ <property name="max-length">8</property> |
|
+ <property name="max-width-chars">32</property> |
|
+ <signal name="notify::text" handler="cc_wwan_pin_entry_changed_cb" swapped="yes" /> |
|
+ <signal name="insert-text" handler="cc_wwan_pin_entry_changed_cb" swapped="yes" /> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="left-attach">1</property> |
|
+ <property name="top-attach">2</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ </child> |
|
+ |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">pin-settings</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ <child> |
|
+ <object class="GtkBox"> |
|
+ <property name="visible">1</property> |
|
+ <property name="orientation">vertical</property> |
|
+ <property name="expand">1</property> |
|
+ <property name="valign">center</property> |
|
+ <property name="halign">center</property> |
|
+ <child> |
|
+ <object class="GtkImage"> |
|
+ <property name="visible">1</property> |
|
+ <property name="pixel-size">128</property> |
|
+ <property name="icon-name">dialog-password-symbolic</property> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkLabel" id=""> |
|
+ <property name="visible">1</property> |
|
+ <property name="label" translatable="yes">Enter current PIN to change SIM lock settings</property> |
|
+ <property name="margin-bottom">24</property> |
|
+ <property name="halign">center</property> |
|
+ <style> |
|
+ <class name="dim-label" /> |
|
+ </style> |
|
+ </object> |
|
+ </child> |
|
+ <child> |
|
+ <object class="GtkEntry" id="pin_entry"> |
|
+ <property name="visible">1</property> |
|
+ <property name="visibility">0</property> |
|
+ <property name="input-purpose">password</property> |
|
+ <property name="input-hints">no-emoji</property> |
|
+ <property name="max-length">8</property> |
|
+ <property name="max-width-chars">32</property> |
|
+ <signal name="notify::text" handler="cc_wwan_pin_entered_cb" swapped="yes" /> |
|
+ <signal name="insert-text" handler="cc_wwan_pin_entry_text_inserted_cb" swapped="yes" /> |
|
+ <!-- We have custom widgets and no actions, so "activates-default" won't work --> |
|
+ <signal name="activate" handler="cc_wwan_pin_apply_clicked_cb" swapped="yes" /> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ <packing> |
|
+ <property name="name">pin-entry</property> |
|
+ </packing> |
|
+ </child> |
|
+ |
|
+ </object> <!-- ./GtkStack pin_settings_stack --> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> |
|
+ </object> |
|
+ </child> <!-- ./internal-child --> |
|
+ |
|
+ <child type="action"> |
|
+ <object class="GtkButton" id="cancel_button"> |
|
+ <property name="visible">1</property> |
|
+ <property name="use-underline">1</property> |
|
+ <property name="label" translatable="yes">_Cancel</property> |
|
+ <signal name="clicked" handler="gtk_widget_hide" swapped="yes"/> |
|
+ </object> |
|
+ </child> |
|
+ <action-widgets> |
|
+ <action-widget response="cancel">cancel_button</action-widget> |
|
+ </action-widgets> |
|
+ |
|
+ </template> |
|
+</interface> |
|
diff --git a/panels/wwan/gnome-wwan-panel.desktop.in.in b/panels/wwan/gnome-wwan-panel.desktop.in.in |
|
new file mode 100644 |
|
index 000000000..351a8edde |
|
--- /dev/null |
|
+++ b/panels/wwan/gnome-wwan-panel.desktop.in.in |
|
@@ -0,0 +1,16 @@ |
|
+[Desktop Entry] |
|
+Name=Mobile Network |
|
+Comment=Configure Telephony and mobile data connections |
|
+Exec=gnome-control-center wwan |
|
+# FIXME |
|
+# Translators: Do NOT translate or transliterate this text (this is an icon file name)! |
|
+Icon=network-cellular-signal-excellent |
|
+Terminal=false |
|
+Type=Application |
|
+NoDisplay=true |
|
+StartupNotify=true |
|
+Categories=GNOME;GTK;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel;X-GNOME-ConnectivitySettings; |
|
+OnlyShowIn=GNOME;Unity; |
|
+StartupNotify=true |
|
+# Translators: Search terms to find the WWAN panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! |
|
+Keywords=cellular;wwan;telephony;sim;mobile; |
|
diff --git a/panels/wwan/meson.build b/panels/wwan/meson.build |
|
new file mode 100644 |
|
index 000000000..8c1b02f26 |
|
--- /dev/null |
|
+++ b/panels/wwan/meson.build |
|
@@ -0,0 +1,61 @@ |
|
+gcr_dep = [dependency('gcr-3')] |
|
+ |
|
+deps = common_deps + network_manager_deps + gcr_dep + [polkit_gobject_dep] |
|
+panels_list += cappletname |
|
+desktop = 'gnome-@0@-panel.desktop'.format(cappletname) |
|
+ |
|
+desktop_in = configure_file( |
|
+ input : desktop + '.in.in', |
|
+ output : desktop + '.in', |
|
+ configuration : desktop_conf |
|
+) |
|
+ |
|
+i18n.merge_file( |
|
+ desktop, |
|
+ type : 'desktop', |
|
+ input : desktop_in, |
|
+ output : desktop, |
|
+ po_dir : po_dir, |
|
+ install : true, |
|
+ install_dir : control_center_desktopdir |
|
+) |
|
+ |
|
+sources = files( |
|
+ 'cc-wwan-panel.c', |
|
+ 'cc-wwan-device.c', |
|
+ 'cc-wwan-data.c', |
|
+ 'cc-wwan-device-page.c', |
|
+ 'cc-wwan-mode-dialog.c', |
|
+ 'cc-wwan-network-dialog.c', |
|
+ 'cc-wwan-details-dialog.c', |
|
+ 'cc-wwan-sim-lock-dialog.c', |
|
+ 'cc-wwan-apn-dialog.c', |
|
+) |
|
+ |
|
+resource_data = files( |
|
+ 'cc-wwan-panel.ui', |
|
+ 'cc-wwan-device-page.ui', |
|
+ 'cc-wwan-mode-dialog.ui', |
|
+ 'cc-wwan-network-dialog.ui', |
|
+ 'cc-wwan-details-dialog.ui', |
|
+ 'cc-wwan-sim-lock-dialog.ui', |
|
+ 'cc-wwan-apn-dialog.ui', |
|
+) |
|
+ |
|
+sources += gnome.compile_resources( |
|
+ 'cc-' + cappletname + '-resources', |
|
+ cappletname + '.gresource.xml', |
|
+ c_name : 'cc_' + cappletname, |
|
+ dependencies : resource_data, |
|
+ export : true |
|
+) |
|
+ |
|
+cflags += '-DGNOMELOCALEDIR="@0@"'.format(control_center_localedir) |
|
+ |
|
+panels_libs += static_library( |
|
+ cappletname, |
|
+ sources : sources, |
|
+ include_directories : [ top_inc, common_inc ], |
|
+ dependencies : deps, |
|
+ c_args : cflags |
|
+) |
|
diff --git a/panels/wwan/wwan.gresource.xml b/panels/wwan/wwan.gresource.xml |
|
new file mode 100644 |
|
index 000000000..f128a164a |
|
--- /dev/null |
|
+++ b/panels/wwan/wwan.gresource.xml |
|
@@ -0,0 +1,12 @@ |
|
+<?xml version="1.0" encoding="UTF-8"?> |
|
+<gresources> |
|
+ <gresource prefix="/org/gnome/control-center/wwan"> |
|
+ <file preprocess="xml-stripblanks">cc-wwan-panel.ui</file> |
|
+ <file preprocess="xml-stripblanks">cc-wwan-device-page.ui</file> |
|
+ <file preprocess="xml-stripblanks">cc-wwan-mode-dialog.ui</file> |
|
+ <file preprocess="xml-stripblanks">cc-wwan-network-dialog.ui</file> |
|
+ <file preprocess="xml-stripblanks">cc-wwan-details-dialog.ui</file> |
|
+ <file preprocess="xml-stripblanks">cc-wwan-sim-lock-dialog.ui</file> |
|
+ <file preprocess="xml-stripblanks">cc-wwan-apn-dialog.ui</file> |
|
+ </gresource> |
|
+</gresources> |
|
diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c |
|
index e23da0b87..e6659b789 100644 |
|
--- a/shell/cc-panel-list.c |
|
+++ b/shell/cc-panel-list.c |
|
@@ -381,6 +381,7 @@ static const gchar * const panel_order[] = { |
|
/* Main page */ |
|
"wifi", |
|
"network", |
|
+ "wwan", |
|
"mobile-broadband", |
|
"bluetooth", |
|
"background", |
|
diff --git a/shell/cc-panel-loader.c b/shell/cc-panel-loader.c |
|
index f20384394..65b6555a1 100644 |
|
--- a/shell/cc-panel-loader.c |
|
+++ b/shell/cc-panel-loader.c |
|
@@ -64,6 +64,9 @@ extern GType cc_user_panel_get_type (void); |
|
#ifdef BUILD_WACOM |
|
extern GType cc_wacom_panel_get_type (void); |
|
#endif /* BUILD_WACOM */ |
|
+#ifdef BUILD_WWAN |
|
+extern GType cc_wwan_panel_get_type (void); |
|
+#endif /* BUILD_WWAN */ |
|
extern GType cc_location_panel_get_type (void); |
|
extern GType cc_camera_panel_get_type (void); |
|
extern GType cc_microphone_panel_get_type (void); |
|
@@ -79,6 +82,9 @@ extern void cc_wifi_panel_static_init_func (void); |
|
#ifdef BUILD_WACOM |
|
extern void cc_wacom_panel_static_init_func (void); |
|
#endif /* BUILD_WACOM */ |
|
+#ifdef BUILD_WWAN |
|
+extern void cc_wwan_panel_static_init_func (void); |
|
+#endif /* BUILD_WWAN */ |
|
|
|
#define PANEL_TYPE(name, get_type, init_func) { name, get_type, init_func } |
|
|
|
@@ -129,6 +135,9 @@ static CcPanelLoaderVtable default_panels[] = |
|
#ifdef BUILD_WACOM |
|
PANEL_TYPE("wacom", cc_wacom_panel_get_type, cc_wacom_panel_static_init_func), |
|
#endif |
|
+#ifdef BUILD_WWAN |
|
+ PANEL_TYPE("wwan", cc_wwan_panel_get_type, cc_wwan_panel_static_init_func), |
|
+#endif |
|
}; |
|
|
|
/* Override for the panel vtable. When NULL, the default_panels will |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 610bf914b5c745c87b0be5c827515e82c07317f9 Mon Sep 17 00:00:00 2001 |
|
From: Mohammed Sadiq <sadiq@sadiqpk.org> |
|
Date: Fri, 4 Oct 2019 16:02:23 +0530 |
|
Subject: [PATCH 3/7] network: Don't show modems supported by cellular panel |
|
|
|
Cellular panel is already handling it |
|
--- |
|
panels/network/cc-network-panel.c | 25 +++++++++++++++++++++++++ |
|
1 file changed, 25 insertions(+) |
|
|
|
diff --git a/panels/network/cc-network-panel.c b/panels/network/cc-network-panel.c |
|
index 01b164ea0..bd4e55df8 100644 |
|
--- a/panels/network/cc-network-panel.c |
|
+++ b/panels/network/cc-network-panel.c |
|
@@ -382,6 +382,27 @@ update_bluetooth_section (CcNetworkPanel *self) |
|
gtk_widget_set_visible (self->container_bluetooth, self->bluetooth_devices->len > 0); |
|
} |
|
|
|
+static gboolean |
|
+wwan_panel_supports_modem (GDBusObject *object) |
|
+{ |
|
+ MMObject *mm_object; |
|
+ MMModem *modem; |
|
+ MMModemCapability capability, supported_capabilities; |
|
+ |
|
+ g_assert (G_IS_DBUS_OBJECT (object)); |
|
+ |
|
+ supported_capabilities = MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE; |
|
+#if MM_CHECK_VERSION (1,14,0) |
|
+ supported_capabilities |= MM_MODEM_CAPABILITY_5GNR; |
|
+#endif |
|
+ |
|
+ mm_object = MM_OBJECT (object); |
|
+ modem = mm_object_get_modem (mm_object); |
|
+ capability = mm_modem_get_current_capabilities (modem); |
|
+ |
|
+ return capability & supported_capabilities; |
|
+} |
|
+ |
|
static void |
|
panel_add_device (CcNetworkPanel *self, NMDevice *device) |
|
{ |
|
@@ -425,6 +446,10 @@ panel_add_device (CcNetworkPanel *self, NMDevice *device) |
|
nm_device_get_udi (device)); |
|
return; |
|
} |
|
+ |
|
+ /* This will be handled by cellular panel */ |
|
+ if (wwan_panel_supports_modem (modem_object)) |
|
+ return; |
|
} |
|
|
|
device_mobile = net_device_mobile_new (self->client, device, modem_object); |
|
-- |
|
2.32.0 |
|
|
|
|
|
From b7a3b8b84641fdc600cc2ab3683da57023ef5e65 Mon Sep 17 00:00:00 2001 |
|
From: Kyle Rankin <kyle.rankin@puri.sm> |
|
Date: Fri, 21 Feb 2020 01:28:13 +0000 |
|
Subject: [PATCH 4/7] Lower WWAN DNS Priority |
|
|
|
The current DNS priority settings for WWAN were set far too low. Most |
|
connections (including WiFi) do not set DNS priority (set to 0) and per |
|
https://developer.gnome.org/NetworkManager/stable/nm-settings.html : |
|
|
|
"A lower value is better (higher priority). Zero selects a globally |
|
configured default value. If the latter is missing or zero too, it |
|
defaults to 50 for VPNs and 100 for other connections." |
|
|
|
By setting both the "low" and "high" settings to 15 and 20 respectively, |
|
the WWAN DNS servers were always appearing above WiFi, even though WiFi |
|
had routing priority. This caused latency and other problems when the |
|
wwan connection was slow because the system would query those DNS |
|
servers before WiFi ones. Beyond that, it would even cause WWAN to |
|
override VPN DNS settings which isn't what we want. |
|
|
|
This change puts the "low priority" setting above the default 100 that |
|
connections get when they don't otherwise set a priority, and the "high |
|
priority" slightly below 100. I did this instead of setting the values |
|
to 0 because I noticed that NM doesn't seem to be aware it should |
|
prioritize WiFi in that case so WWAN DNS servers were still sometimes |
|
taking precedence. |
|
--- |
|
panels/wwan/cc-wwan-data.c | 17 ++++++++++++++--- |
|
1 file changed, 14 insertions(+), 3 deletions(-) |
|
|
|
diff --git a/panels/wwan/cc-wwan-data.c b/panels/wwan/cc-wwan-data.c |
|
index 0be8f3403..4062d78fd 100644 |
|
--- a/panels/wwan/cc-wwan-data.c |
|
+++ b/panels/wwan/cc-wwan-data.c |
|
@@ -47,9 +47,20 @@ |
|
* of #CcWwanData changes when SIM is changed. |
|
*/ |
|
|
|
-/* Priority for connections. larger the number, lower the priority */ |
|
-#define CC_WWAN_DNS_PRIORITY_LOW (20) |
|
-#define CC_WWAN_DNS_PRIORITY_HIGH (15) |
|
+/* |
|
+ * Priority for connections. The larger the number, the lower the priority |
|
+ * https://developer.gnome.org/NetworkManager/stable/nm-settings.html: |
|
+ * |
|
+ * A lower value is better (higher priority). Zero selects a globally |
|
+ * configured default value. If the latter is missing or zero too, it |
|
+ * defaults to 50 for VPNs and 100 for other connections. |
|
+ * |
|
+ * Since WiFi and other network connections will likely get the default |
|
+ * setting of 100, set WWAN DNS priorities higher than the default, with |
|
+ * room to allow multiple modems to set priority above/below each other. |
|
+ */ |
|
+#define CC_WWAN_DNS_PRIORITY_LOW (120) |
|
+#define CC_WWAN_DNS_PRIORITY_HIGH (115) |
|
|
|
/* These are to be set as route metric */ |
|
#define CC_WWAN_ROUTE_PRIORITY_LOW (1050) |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 0f38f32b98ae946b8259e3232e311d4f743acaba Mon Sep 17 00:00:00 2001 |
|
From: Sebastian Krzyszkowiak <sebastian.krzyszkowiak@puri.sm> |
|
Date: Mon, 6 Jul 2020 04:33:30 +0200 |
|
Subject: [PATCH 5/7] wwan: Fix signal strength display when extended signal |
|
retrieval is disabled |
|
|
|
MMModemSignal interface is used to retrieve extended signal information that |
|
requires periodic polling. Therefore, it needs to be manually enabled in order |
|
to use. There if a fallback to use mm_modem_get_signal_quality when MMModemSignal |
|
interface is unavailable, but it didn't check whether it's actually enabled, |
|
leaving the UI with empty label. |
|
--- |
|
panels/wwan/cc-wwan-device.c | 6 +++++- |
|
1 file changed, 5 insertions(+), 1 deletion(-) |
|
|
|
diff --git a/panels/wwan/cc-wwan-device.c b/panels/wwan/cc-wwan-device.c |
|
index 31baff95c..55a627a5a 100644 |
|
--- a/panels/wwan/cc-wwan-device.c |
|
+++ b/panels/wwan/cc-wwan-device.c |
|
@@ -1183,12 +1183,16 @@ cc_wwan_device_dup_signal_string (CcWwanDevice *self) |
|
GString *str; |
|
gdouble value; |
|
gboolean recent; |
|
+ guint refresh_rate; |
|
|
|
g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); |
|
|
|
modem_signal = mm_object_peek_modem_signal (self->mm_object); |
|
|
|
- if (!modem_signal) |
|
+ if (modem_signal) |
|
+ refresh_rate = mm_modem_signal_get_rate (modem_signal); |
|
+ |
|
+ if (!modem_signal || !refresh_rate) |
|
return g_strdup_printf ("%d%%", mm_modem_get_signal_quality (self->modem, &recent)); |
|
|
|
str = g_string_new (""); |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 99bbe06a25a523898dde7370274430e7502be53e Mon Sep 17 00:00:00 2001 |
|
From: Mohammed Sadiq <sadiq@sadiqpk.org> |
|
Date: Sat, 14 Aug 2021 13:39:33 +0530 |
|
Subject: [PATCH 6/7] wwan: Fix a typo |
|
|
|
Fixes https://gitlab.gnome.org/GNOME/gnome-control-center/-/commit/dc840f0aec346f3fb297789eb1641255574c47a4#note_1249116 |
|
--- |
|
panels/wwan/cc-wwan-apn-dialog.ui | 2 +- |
|
1 file changed, 1 insertion(+), 1 deletion(-) |
|
|
|
diff --git a/panels/wwan/cc-wwan-apn-dialog.ui b/panels/wwan/cc-wwan-apn-dialog.ui |
|
index fb8432bc6..9ac07ce38 100644 |
|
--- a/panels/wwan/cc-wwan-apn-dialog.ui |
|
+++ b/panels/wwan/cc-wwan-apn-dialog.ui |
|
@@ -211,7 +211,7 @@ |
|
<property name="visible">1</property> |
|
<property name="halign">end</property> |
|
<property name="valign">center</property> |
|
- <property name="label" translatable="yes">Passsword</property> |
|
+ <property name="label" translatable="yes">Password</property> |
|
<style> |
|
<class name="dim-label" /> |
|
</style> |
|
-- |
|
2.32.0 |
|
|
|
|
|
From b1cf8916b2569aa6c3b7f724eff37f198ed37b73 Mon Sep 17 00:00:00 2001 |
|
From: Mohammed Sadiq <sadiq@sadiqpk.org> |
|
Date: Sat, 14 Aug 2021 13:54:33 +0530 |
|
Subject: [PATCH 7/7] wwan: Avoid translation of some strings |
|
|
|
Many strings are not shown in the UI. Let's not overwhelm translators |
|
--- |
|
panels/wwan/cc-wwan-errors-private.h | 50 ++++++++++++++-------------- |
|
1 file changed, 25 insertions(+), 25 deletions(-) |
|
|
|
diff --git a/panels/wwan/cc-wwan-errors-private.h b/panels/wwan/cc-wwan-errors-private.h |
|
index 761b82f35..076482d1f 100644 |
|
--- a/panels/wwan/cc-wwan-errors-private.h |
|
+++ b/panels/wwan/cc-wwan-errors-private.h |
|
@@ -39,12 +39,12 @@ typedef struct { |
|
static ErrorTable me_errors[] = { |
|
{ MM_MOBILE_EQUIPMENT_ERROR_PHONE_FAILURE, N_("Phone failure") }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_NO_CONNECTION, N_("No connection to phone") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_LINK_RESERVED, N_("Phone-adaptor link reserved") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_LINK_RESERVED, "Phone-adaptor link reserved" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED, N_("Operation not allowed") }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, N_("Operation not supported") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_PH_SIM_PIN, N_("PH-SIM PIN required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_PH_FSIM_PIN, N_("PH-FSIM PIN required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_PH_FSIM_PUK, N_("PH-FSIM PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_PH_SIM_PIN, "PH-SIM PIN required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_PH_FSIM_PIN, "PH-FSIM PIN required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_PH_FSIM_PUK, "PH-FSIM PUK required" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, N_("SIM not inserted") }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN, N_("SIM PIN required") }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK, N_("SIM PUK required") }, |
|
@@ -54,34 +54,34 @@ static ErrorTable me_errors[] = { |
|
{ MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD, N_("Incorrect password") }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN2, N_("SIM PIN2 required") }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK2, N_("SIM PUK2 required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FULL, N_("Memory full") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_INVALID_INDEX, N_("Invalid index") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FULL, "Memory full" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_INVALID_INDEX, "Invalid index" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_NOT_FOUND, N_("Not found") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FAILURE, N_("Memory failure") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FAILURE, "Memory failure" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK, N_("No network service") }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, N_("Network timeout") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED, N_("Network not allowed - emergency calls only") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_PIN, N_("Network personalization PIN required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_PUK, N_("Network personalization PUK required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_SUBSET_PIN, N_("Network subset personalization PIN required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_SUBSET_PUK, N_("Network subset personalization PUK required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_SERVICE_PIN, N_("Service provider personalization PIN required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_SERVICE_PUK, N_("Service provider personalization PUK required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_CORP_PIN, N_("Corporate personalization PIN required") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_CORP_PUK, N_("Corporate personalization PUK required") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED, "Network not allowed - emergency calls only" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_PIN, "Network personalization PIN required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_PUK, "Network personalization PUK required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_SUBSET_PIN, "Network subset personalization PIN required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_NETWORK_SUBSET_PUK, "Network subset personalization PUK required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SERVICE_PIN, "Service provider personalization PIN required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_SERVICE_PUK, "Service provider personalization PUK required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_CORP_PIN, "Corporate personalization PIN required" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_CORP_PUK, "Corporate personalization PUK required" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN, N_("Unknown error") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_ILLEGAL_MS, N_("Illegal MS") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_ILLEGAL_ME, N_("Illegal ME") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_ILLEGAL_MS, "Illegal MS" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_ILLEGAL_ME, "Illegal ME" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_NOT_ALLOWED, N_("GPRS services not allowed") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_PLMN_NOT_ALLOWED, N_("PLMN not allowed") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_LOCATION_NOT_ALLOWED, N_("Location area not allowed") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_PLMN_NOT_ALLOWED, "PLMN not allowed" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_LOCATION_NOT_ALLOWED, "Location area not allowed" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_GPRS_ROAMING_NOT_ALLOWED, N_("Roaming not allowed in this location area") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_NOT_SUPPORTED, N_("Service option not supported") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_NOT_SUBSCRIBED, N_("Requested service option not subscribed") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_OUT_OF_ORDER, N_("Service option temporarily out of order") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_NOT_SUPPORTED, "Service option not supported" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_NOT_SUBSCRIBED, "Requested service option not subscribed" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_SERVICE_OPTION_OUT_OF_ORDER, "Service option temporarily out of order" }, |
|
{ MM_MOBILE_EQUIPMENT_ERROR_GPRS_UNKNOWN, N_("Unspecified GPRS error") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_PDP_AUTH_FAILURE, N_("PDP authentication failure") }, |
|
- { MM_MOBILE_EQUIPMENT_ERROR_GPRS_INVALID_MOBILE_CLASS, N_("Invalid mobile class") }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_PDP_AUTH_FAILURE, "PDP authentication failure" }, |
|
+ { MM_MOBILE_EQUIPMENT_ERROR_GPRS_INVALID_MOBILE_CLASS, "Invalid mobile class" }, |
|
}; |
|
|
|
static inline const gchar * |
|
-- |
|
2.32.0 |
|
|
|
|