From 0a43f3bce775d5337ae5a2d5407484eb76d5235f Mon Sep 17 00:00:00 2001 From: JOSEF OUANO Date: Thu, 30 May 2024 15:41:57 +0900 Subject: [PATCH 1/9] wwan: Add Primary Sim Slot in Mobile Network Page Co-authored by: Felipe Borges --- panels/wwan/cc-wwan-device-page.blp | 5 + panels/wwan/cc-wwan-device-page.c | 11 ++ panels/wwan/cc-wwan-device.c | 60 +++++++ panels/wwan/cc-wwan-device.h | 14 ++ panels/wwan/cc-wwan-sim-slot-dialog.c | 235 +++++++++++++++++++++++++ panels/wwan/cc-wwan-sim-slot-dialog.h | 40 +++++ panels/wwan/cc-wwan-sim-slot-dialog.ui | 52 ++++++ panels/wwan/cc-wwan-sim-slot-row.c | 90 ++++++++++ panels/wwan/cc-wwan-sim-slot-row.h | 37 ++++ panels/wwan/meson.build | 2 + panels/wwan/wwan.gresource.xml | 1 + 11 files changed, 547 insertions(+) create mode 100644 panels/wwan/cc-wwan-sim-slot-dialog.c create mode 100644 panels/wwan/cc-wwan-sim-slot-dialog.h create mode 100644 panels/wwan/cc-wwan-sim-slot-dialog.ui create mode 100644 panels/wwan/cc-wwan-sim-slot-row.c create mode 100644 panels/wwan/cc-wwan-sim-slot-row.h diff --git a/panels/wwan/cc-wwan-device-page.blp b/panels/wwan/cc-wwan-device-page.blp index 8d3ce1de9b..701a4d045e 100644 --- a/panels/wwan/cc-wwan-device-page.blp +++ b/panels/wwan/cc-wwan-device-page.blp @@ -122,6 +122,11 @@ template $CcWwanDevicePage: Box { show-arrow: true; title: _("M_odem Details"); } + + $CcListRow sim_slot_row { + show-arrow: true; + title: _("S_IM Slot"); + } } } }; diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c index 36b4766a10..c90aa56fd1 100644 --- a/panels/wwan/cc-wwan-device-page.c +++ b/panels/wwan/cc-wwan-device-page.c @@ -37,6 +37,7 @@ #include "cc-wwan-network-dialog.h" #include "cc-wwan-details-dialog.h" #include "cc-wwan-sim-lock-dialog.h" +#include "cc-wwan-sim-slot-dialog.h" #include "cc-wwan-apn-dialog.h" #include "cc-wwan-device-page.h" #include "cc-wwan-resources.h" @@ -70,6 +71,7 @@ struct _CcWwanDevicePage CcListRow *network_name_row; GtkListBox *network_settings_list; CcListRow *sim_lock_row; + CcListRow *sim_slot_row; GtkButton *unlock_button; AdwToastOverlay *toast_overlay; @@ -82,6 +84,7 @@ struct _CcWwanDevicePage GtkWindow *network_mode_dialog; GtkWindow *network_dialog; GtkWindow *sim_lock_dialog; + GtkWindow *sim_slot_dialog; gint sim_index; /* Set if a change is triggered in a signal’s callback, @@ -390,6 +393,7 @@ wwan_advanced_settings_activated_cb (CcWwanDevicePage *self, CcListRow *row) { GtkWindow *top_level; + GtkWidget *sim_slot_dialog; top_level = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))); @@ -404,6 +408,11 @@ wwan_advanced_settings_activated_cb (CcWwanDevicePage *self, AdwDialog *dialog = cc_wwan_details_dialog_new (self->device); adw_dialog_present (dialog, GTK_WIDGET (top_level)); } + else if (row == self->sim_slot_row) + { + sim_slot_dialog = cc_wwan_sim_slot_dialog_new (GTK_BOX (self), self->device); + adw_dialog_present (ADW_DIALOG (sim_slot_dialog), GTK_WIDGET (self)); + } else if (row == self->apn_settings_row) { wwan_data_show_apn_dialog (self); @@ -535,6 +544,7 @@ cc_wwan_device_page_dispose (GObject *object) g_clear_pointer (&self->network_mode_dialog, gtk_window_destroy); g_clear_pointer (&self->network_dialog, gtk_window_destroy); g_clear_pointer (&self->sim_lock_dialog, gtk_window_destroy); + g_clear_pointer (&self->sim_slot_dialog, gtk_window_destroy); g_clear_object (&self->wwan_proxy); g_clear_object (&self->device); @@ -577,6 +587,7 @@ cc_wwan_device_page_class_init (CcWwanDevicePageClass *klass) 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, sim_slot_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); diff --git a/panels/wwan/cc-wwan-device.c b/panels/wwan/cc-wwan-device.c index 26092b6bcd..5823668618 100644 --- a/panels/wwan/cc-wwan-device.c +++ b/panels/wwan/cc-wwan-device.c @@ -90,6 +90,31 @@ enum { static GParamSpec *properties[N_PROPS]; +void +cc_wwan_device_set_primary_sim_slot (CcWwanDevice *self, guint sim_slot, GCancellable *cancellable) +{ + GError *error = NULL; + + mm_modem_set_primary_sim_slot_sync (self->modem, sim_slot, cancellable, &error); + + if (error) + g_warning ("Error:%s", error->message); +} + +GPtrArray * +cc_wwan_device_get_sim_slots (CcWwanDevice *self, GCancellable *cancellable) +{ + GError *error = NULL; + GPtrArray *sim_slots; + + sim_slots = mm_modem_list_sim_slots_sync (self->modem, cancellable, &error); + + if (error) + g_warning ("Error:%s", error->message); + + return sim_slots; +} + static void cc_wwan_device_state_changed_cb (CcWwanDevice *self) { @@ -974,6 +999,41 @@ cc_wwan_device_get_supported_modes (CcWwanDevice *self, return TRUE; } +gchar * +cc_wwan_device_get_string_from_slots (CcWwanDevice *self, + MMSim *sim, + guint slot_num) +{ + g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); + + MMSimType simType; + gchar *slot_number; + GString *str, *mmSimType; + + str = g_string_sized_new (5); + simType = mm_sim_get_sim_type (sim); + slot_number = g_strdup_printf ("Slot %d", slot_num); + g_string_append (str, slot_number); + + switch(simType) + { + case MM_SIM_TYPE_UNKNOWN: + mmSimType = g_string_append (str, _(" [Unknown]")); + break; + case MM_SIM_TYPE_PHYSICAL: + mmSimType = g_string_append (str, _(" [Physical]")); + break; + case MM_SIM_TYPE_ESIM: + mmSimType = g_string_append (str, _(" [ESIM]")); + break; + default: + mmSimType = g_string_append (str, _(" [Unknown]")); + break; + } + + return g_string_free (str, FALSE); +} + gchar * cc_wwan_device_get_string_from_mode (CcWwanDevice *self, MMModemMode allowed, diff --git a/panels/wwan/cc-wwan-device.h b/panels/wwan/cc-wwan-device.h index e484bcf30f..1835eb7fc7 100644 --- a/panels/wwan/cc-wwan-device.h +++ b/panels/wwan/cc-wwan-device.h @@ -43,6 +43,12 @@ typedef enum CC_WWAN_REGISTRATION_STATE_DENIED } CcWwanState; +typedef enum +{ + CC_WWAN_SIM_SLOT_1, + CC_WWAN_SIM_SLOT_2 +} CcWwanSimSlot; + typedef struct _CcWwanData CcWwanData; #define CC_TYPE_WWAN_DEVICE (cc_wwan_device_get_type()) @@ -125,6 +131,9 @@ gboolean cc_wwan_device_set_current_mode_finish (CcWwanDevice *self gchar *cc_wwan_device_get_string_from_mode (CcWwanDevice *self, MMModemMode allowed, MMModemMode preferred); +gchar *cc_wwan_device_get_string_from_slots (CcWwanDevice *self, + MMSim *sim, + guint slot_num); void cc_wwan_device_scan_networks (CcWwanDevice *self, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -148,5 +157,10 @@ 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); +GPtrArray *cc_wwan_device_get_sim_slots (CcWwanDevice *self, + GCancellable *cancellable); +void cc_wwan_device_set_primary_sim_slot (CcWwanDevice *self, + guint sim_slot, + GCancellable *cancellable); G_END_DECLS diff --git a/panels/wwan/cc-wwan-sim-slot-dialog.c b/panels/wwan/cc-wwan-sim-slot-dialog.c new file mode 100644 index 0000000000..af2cf22146 --- /dev/null +++ b/panels/wwan/cc-wwan-sim-slot-dialog.c @@ -0,0 +1,235 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* cc-wwan-sim-slot-dialog.c + * + * Copyright (C) 2024 Josef Vincent Ouano + * + * 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 . + * + * Author(s): + * Josef Vincent Ouano + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "cc-network-sim-slot-dialog" + +#include +#include +#include + +#include "cc-wwan-sim-slot-dialog.h" +#include "cc-wwan-sim-slot-row.h" +#include "cc-wwan-resources.h" +#include "cc-wwan-device.h" + +/** + * @short_description: WWAN sim slot selection dialog + */ + +struct _CcWwanSimSlotDialog +{ + AdwDialog parent_instance; + + CcWwanDevice *device; + + AdwPreferencesGroup *sim_slot_list; + CcWwanSimSlotRow *selected_row; + + GCancellable *cancellable; +}; + +G_DEFINE_TYPE (CcWwanSimSlotDialog, cc_wwan_sim_slot_dialog, ADW_TYPE_DIALOG) + +enum { + PROP_0, + PROP_DEVICE, + N_PROPS +}; + +static GParamSpec *properties[N_PROPS]; + +static void +cc_wwan_sim_slot_row_class_init (CcWwanSimSlotRowClass *klass) +{ +} + +static void +cc_wwan_sim_slot_row_init (CcWwanSimSlotRow *row) +{ +} + +static void +cc_wwan_sim_slot_changed_cb (CcWwanSimSlotDialog *self, + CcWwanSimSlotRow *row) +{ + g_assert (CC_IS_WWAN_SIM_SLOT_DIALOG (self)); + + if (row == self->selected_row) + return; + + cc_wwan_sim_slot_row_update_icon (row, TRUE); + + if (self->selected_row) { + cc_wwan_sim_slot_row_update_icon (self->selected_row, FALSE); + } + + self->selected_row = row; +} + +static void +cc_wwan_sim_slot_dialog_ok_clicked_cb (CcWwanSimSlotDialog *self) +{ + g_assert (CC_IS_WWAN_SIM_SLOT_DIALOG (self)); + + if (self->selected_row) + { + cc_wwan_device_set_primary_sim_slot (self->device, cc_wwan_sim_slot_row_get_slot_num (self->selected_row), self->cancellable); + } + else + { + g_return_if_reached (); + } + + adw_dialog_close (ADW_DIALOG (self)); +} + +static CcWwanSimSlotRow * +cc_wwan_sim_slot_dialog_row_new (CcWwanSimSlotDialog *self, MMSim *sim, guint slot_num) +{ + CcWwanSimSlotRow *row; + g_autofree gchar *slot_label = NULL; + + slot_label = cc_wwan_device_get_string_from_slots (self->device, sim, slot_num); + row = cc_wwan_sim_slot_row_new (slot_label, slot_num); + + return row; +} + +static void +cc_wwan_sim_slot_dialog_update (CcWwanSimSlotDialog *self) +{ + GPtrArray *sim_slots; + gboolean simActive = false; + + sim_slots = g_ptr_array_new (); + sim_slots = cc_wwan_device_get_sim_slots (self->device, self->cancellable); + + for (int i = 0; i < sim_slots->len; i++) + { + MMSim *sim; + CcWwanSimSlotRow *row; + + sim = MM_SIM (g_ptr_array_index (sim_slots, i)); + row = cc_wwan_sim_slot_dialog_row_new (self, sim, i+1); + + simActive = mm_sim_get_active (sim); + if (simActive == true) { + cc_wwan_sim_slot_row_update_icon (row, TRUE); + self->selected_row = row; + } + else if (simActive == false) { + cc_wwan_sim_slot_row_update_icon (row, FALSE); + } + + g_signal_connect_swapped (G_OBJECT (row), "activated", G_CALLBACK (cc_wwan_sim_slot_changed_cb), self); + adw_preferences_group_add (self->sim_slot_list, GTK_WIDGET (row)); + } +} + +static void +cc_wwan_sim_slot_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CcWwanSimSlotDialog *self = (CcWwanSimSlotDialog *)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_slot_dialog_constructed (GObject *object) +{ + CcWwanSimSlotDialog *self = CC_WWAN_SIM_SLOT_DIALOG (object); + + G_OBJECT_CLASS (cc_wwan_sim_slot_dialog_parent_class)->constructed (object); + cc_wwan_sim_slot_dialog_update (self); +} + +static void +cc_wwan_sim_slot_dialog_dispose (GObject *object) +{ + CcWwanSimSlotDialog *self = CC_WWAN_SIM_SLOT_DIALOG (object); + + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->device); + + G_OBJECT_CLASS (cc_wwan_sim_slot_dialog_parent_class)->dispose (object); +} + +static void +cc_wwan_sim_slot_dialog_class_init (CcWwanSimSlotDialogClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = cc_wwan_sim_slot_dialog_set_property; + object_class->constructed = cc_wwan_sim_slot_dialog_constructed; + object_class->dispose = cc_wwan_sim_slot_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-sim-slot-dialog.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcWwanSimSlotDialog, sim_slot_list); + + gtk_widget_class_bind_template_callback (widget_class, cc_wwan_sim_slot_dialog_ok_clicked_cb); +} + +static void +cc_wwan_sim_slot_dialog_init (CcWwanSimSlotDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + self->cancellable = g_cancellable_new (); +} + +GtkWidget * +cc_wwan_sim_slot_dialog_new (GtkBox *parent_window, + CcWwanDevice *device) +{ + CcWwanSimSlotDialog *self; + + self = g_object_new (CC_TYPE_WWAN_SIM_SLOT_DIALOG, + "device", device, + NULL); + return GTK_WIDGET (self); +} diff --git a/panels/wwan/cc-wwan-sim-slot-dialog.h b/panels/wwan/cc-wwan-sim-slot-dialog.h new file mode 100644 index 0000000000..173e86d274 --- /dev/null +++ b/panels/wwan/cc-wwan-sim-slot-dialog.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* cc-wwan-sim-slot-dialog.h + * + * Copyright (C) 2024 Josef Vincent Ouano + * + * 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 . + * + * Author(s): + * Josef Vincent Ouano + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include + +#include "cc-wwan-device.h" + +G_BEGIN_DECLS + +#define CC_TYPE_WWAN_SIM_SLOT_DIALOG (cc_wwan_sim_slot_dialog_get_type()) +G_DECLARE_FINAL_TYPE (CcWwanSimSlotDialog, cc_wwan_sim_slot_dialog, CC, WWAN_SIM_SLOT_DIALOG, AdwDialog) + +GtkWidget *cc_wwan_sim_slot_dialog_new (GtkBox *parent_window, + CcWwanDevice *device); + +G_END_DECLS \ No newline at end of file diff --git a/panels/wwan/cc-wwan-sim-slot-dialog.ui b/panels/wwan/cc-wwan-sim-slot-dialog.ui new file mode 100644 index 0000000000..0fb7d50b49 --- /dev/null +++ b/panels/wwan/cc-wwan-sim-slot-dialog.ui @@ -0,0 +1,52 @@ + + + + + diff --git a/panels/wwan/cc-wwan-sim-slot-row.c b/panels/wwan/cc-wwan-sim-slot-row.c new file mode 100644 index 0000000000..3e3ef84ff6 --- /dev/null +++ b/panels/wwan/cc-wwan-sim-slot-row.c @@ -0,0 +1,90 @@ +/* cc-applications-row.c + * + * Copyright 2024 Josef Vincent Ouano + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include + +#include "cc-wwan-sim-slot-row.h" + +struct _CcWwanSimSlotRow +{ + AdwActionRow parent_instance; + GtkImage *ok_emblem; + guint slot_num; +}; + +G_DEFINE_TYPE (CcWwanSimSlotRow, cc_wwan_sim_slot_row, ADW_TYPE_ACTION_ROW) + +static void +cc_wwan_sim_slot_row_finalize (GObject *object) +{ + CcWwanSimSlotRow *self = CC_WWAN_SIM_SLOT_ROW (object); + G_OBJECT_CLASS (cc_wwan_sim_slot_row_parent_class)->finalize (object); +} + +static void +cc_wwan_sim_slot_row_class_init (CcWwanSimSlotRowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = cc_wwan_sim_slot_row_finalize; +} + +static void +cc_wwan_sim_slot_row_init (CcWwanSimSlotRow *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +void +cc_wwan_sim_slot_row_update_icon (CcWwanSimSlotRow *self, gboolean isEnabled) +{ + g_return_if_fail (CC_IS_WWAN_SIM_SLOT_ROW (self)); + + gtk_widget_set_visible (GTK_WIDGET (self->ok_emblem), isEnabled); +} + +guint +cc_wwan_sim_slot_row_get_slot_num (CcWwanSimSlotRow *self) +{ + return self->slot_num; +} + +CcWwanSimSlotRow * +cc_wwan_sim_slot_row_new (gchar *slot_label, guint slot_num) +{ + CcWwanSimSlotRow *self; + GtkWidget *box, *image; + + self = g_object_new (CC_TYPE_WWAN_SIM_SLOT_ROW, NULL); + self->slot_num = slot_num; + + adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), slot_label); + + image = gtk_image_new_from_icon_name ("emblem-ok-symbolic"); + self->ok_emblem = GTK_IMAGE (image); + adw_action_row_add_suffix (ADW_ACTION_ROW (self), GTK_WIDGET (self->ok_emblem)); + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + adw_action_row_set_activatable_widget (ADW_ACTION_ROW (self), box); + + return self; +} diff --git a/panels/wwan/cc-wwan-sim-slot-row.h b/panels/wwan/cc-wwan-sim-slot-row.h new file mode 100644 index 0000000000..6c3043cca1 --- /dev/null +++ b/panels/wwan/cc-wwan-sim-slot-row.h @@ -0,0 +1,37 @@ +/* cc-wwan-sim-slot-row.h + * + * Copyright 2024 Josef Vincent Ouano + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define CC_TYPE_WWAN_SIM_SLOT_ROW (cc_wwan_sim_slot_row_get_type()) +G_DECLARE_FINAL_TYPE (CcWwanSimSlotRow, cc_wwan_sim_slot_row, CC, WWAN_SIM_SLOT_ROW, AdwActionRow) + +CcWwanSimSlotRow* cc_wwan_sim_slot_row_new (gchar *slot_label, guint slot_num); + +void cc_wwan_sim_slot_row_update_icon (CcWwanSimSlotRow *self, gboolean isEnabled); + +guint cc_wwan_sim_slot_row_get_slot_num (CcWwanSimSlotRow *self); + +G_END_DECLS \ No newline at end of file diff --git a/panels/wwan/meson.build b/panels/wwan/meson.build index cbadae59de..1a35710ba3 100644 --- a/panels/wwan/meson.build +++ b/panels/wwan/meson.build @@ -43,6 +43,8 @@ sources = files( 'cc-wwan-details-dialog.c', 'cc-wwan-sim-lock-dialog.c', 'cc-wwan-apn-dialog.c', + 'cc-wwan-sim-slot-dialog.c', + 'cc-wwan-sim-slot-row.c', ) sources += gnome.compile_resources( diff --git a/panels/wwan/wwan.gresource.xml b/panels/wwan/wwan.gresource.xml index f128a164a4..d2ed89a76f 100644 --- a/panels/wwan/wwan.gresource.xml +++ b/panels/wwan/wwan.gresource.xml @@ -8,5 +8,6 @@ cc-wwan-details-dialog.ui cc-wwan-sim-lock-dialog.ui cc-wwan-apn-dialog.ui + cc-wwan-sim-slot-dialog.ui -- GitLab From 23234d8a3275e5f387c0d570b9b229111a1e4bde Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Fri, 6 Jun 2025 16:05:43 +0200 Subject: [PATCH 2/9] wwan: Convert "Sim Slot" dialog into a combo row This does a better job at indicating that only one slot can be chosen as primary. Also simpler. --- panels/wwan/cc-wwan-device-page.blp | 9 +- panels/wwan/cc-wwan-device-page.c | 58 +++++- panels/wwan/cc-wwan-device.c | 35 ---- panels/wwan/cc-wwan-device.h | 9 - panels/wwan/cc-wwan-sim-slot-dialog.c | 235 ------------------------- panels/wwan/cc-wwan-sim-slot-dialog.h | 40 ----- panels/wwan/cc-wwan-sim-slot-dialog.ui | 52 ------ panels/wwan/cc-wwan-sim-slot-row.c | 90 ---------- panels/wwan/cc-wwan-sim-slot-row.h | 37 ---- panels/wwan/meson.build | 2 - panels/wwan/wwan.gresource.xml | 1 - 11 files changed, 56 insertions(+), 512 deletions(-) delete mode 100644 panels/wwan/cc-wwan-sim-slot-dialog.c delete mode 100644 panels/wwan/cc-wwan-sim-slot-dialog.h delete mode 100644 panels/wwan/cc-wwan-sim-slot-dialog.ui delete mode 100644 panels/wwan/cc-wwan-sim-slot-row.c delete mode 100644 panels/wwan/cc-wwan-sim-slot-row.h diff --git a/panels/wwan/cc-wwan-device-page.blp b/panels/wwan/cc-wwan-device-page.blp index 701a4d045e..bb8964c5bb 100644 --- a/panels/wwan/cc-wwan-device-page.blp +++ b/panels/wwan/cc-wwan-device-page.blp @@ -123,9 +123,12 @@ template $CcWwanDevicePage: Box { title: _("M_odem Details"); } - $CcListRow sim_slot_row { - show-arrow: true; - title: _("S_IM Slot"); + Adw.ComboRow sim_slot_row { + use-underline: true; + title: _("Primary S_IM Slot"); + notify::selected => $wwan_device_set_primary_sim_slot_cb(template); + + model: StringList sim_slot_string_list {}; } } } diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c index c90aa56fd1..0deaed08c7 100644 --- a/panels/wwan/cc-wwan-device-page.c +++ b/panels/wwan/cc-wwan-device-page.c @@ -37,7 +37,6 @@ #include "cc-wwan-network-dialog.h" #include "cc-wwan-details-dialog.h" #include "cc-wwan-sim-lock-dialog.h" -#include "cc-wwan-sim-slot-dialog.h" #include "cc-wwan-apn-dialog.h" #include "cc-wwan-device-page.h" #include "cc-wwan-resources.h" @@ -71,7 +70,8 @@ struct _CcWwanDevicePage CcListRow *network_name_row; GtkListBox *network_settings_list; CcListRow *sim_lock_row; - CcListRow *sim_slot_row; + AdwComboRow *sim_slot_row; + GtkStringList *sim_slot_string_list; GtkButton *unlock_button; AdwToastOverlay *toast_overlay; @@ -393,7 +393,6 @@ wwan_advanced_settings_activated_cb (CcWwanDevicePage *self, CcListRow *row) { GtkWindow *top_level; - GtkWidget *sim_slot_dialog; top_level = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))); @@ -408,15 +407,14 @@ wwan_advanced_settings_activated_cb (CcWwanDevicePage *self, AdwDialog *dialog = cc_wwan_details_dialog_new (self->device); adw_dialog_present (dialog, GTK_WIDGET (top_level)); } - else if (row == self->sim_slot_row) - { - sim_slot_dialog = cc_wwan_sim_slot_dialog_new (GTK_BOX (self), self->device); - adw_dialog_present (ADW_DIALOG (sim_slot_dialog), GTK_WIDGET (self)); - } else if (row == self->apn_settings_row) { wwan_data_show_apn_dialog (self); } + else if (GTK_WIDGET (row) == GTK_WIDGET (self->sim_slot_row)) + { + /* NOP handling sim_slot_row, since it is a combo row. */ + } else { g_return_if_reached (); @@ -487,6 +485,47 @@ cc_wwan_locks_changed_cb (CcWwanDevicePage *self) cc_wwan_device_page_update (self); } +static void +wwan_device_set_primary_sim_slot_cb (CcWwanDevicePage *self) +{ + guint primary_slot = adw_combo_row_get_selected (self->sim_slot_row); + + cc_wwan_device_set_primary_sim_slot (self->device, primary_slot, NULL); // FIXME: cancellable + g_debug ("Setting primary sim slot to %d", primary_slot); +} + +static void +cc_wwan_update_sim_slots_row (CcWwanDevicePage *self) +{ + g_autoptr(GPtrArray) sim_slots = cc_wwan_device_get_sim_slots (self->device, NULL); // FIXME: cancellable + int i; + + /* There's nothing the user can do if we get zero slots. Hide the row. */ + gtk_widget_set_visible (GTK_WIDGET (self->sim_slot_row), sim_slots->len > 0); + + for (i = 0; i < sim_slots->len; i++) { + MMSim *sim = MM_SIM (g_ptr_array_index (sim_slots, i)); + MMSimType sim_type = mm_sim_get_sim_type (sim); + g_autofree gchar *sim_type_label = NULL; + g_autofree gchar *sim_label = NULL; + + if (sim_type == MM_SIM_TYPE_PHYSICAL) + sim_type_label = g_strdup_printf ("[%s]", _("Physical")); + else if (sim_type == MM_SIM_TYPE_ESIM) + sim_type_label = g_strdup ("[ESIM]"); /* Let's not translate ESIM. */ + else + sim_type_label = g_strdup_printf ("[%s]", _("Unknown")); + + /* Translators: This refers to a physical or esim slot in a modem. + * For example: "Slot 1 Physical" or "Slot 2 ESIM". */ + sim_label = g_strdup_printf (_("Slot %d %s"), i+1, sim_type_label); + gtk_string_list_append (self->sim_slot_string_list, sim_label); + + if (mm_sim_get_active (sim)) + adw_combo_row_set_selected (self->sim_slot_row, i); + } +} + static void cc_wwan_device_page_set_property (GObject *object, guint prop_id, @@ -533,6 +572,7 @@ cc_wwan_device_page_constructed (GObject *object) cc_wwan_device_page_update (self); cc_wwan_locks_changed_cb (self); + cc_wwan_update_sim_slots_row (self); } static void @@ -588,9 +628,11 @@ cc_wwan_device_page_class_init (CcWwanDevicePageClass *klass) 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, sim_slot_row); + gtk_widget_class_bind_template_child (widget_class, CcWwanDevicePage, sim_slot_string_list); 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_device_set_primary_sim_slot_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); diff --git a/panels/wwan/cc-wwan-device.c b/panels/wwan/cc-wwan-device.c index 5823668618..1debe41c37 100644 --- a/panels/wwan/cc-wwan-device.c +++ b/panels/wwan/cc-wwan-device.c @@ -999,41 +999,6 @@ cc_wwan_device_get_supported_modes (CcWwanDevice *self, return TRUE; } -gchar * -cc_wwan_device_get_string_from_slots (CcWwanDevice *self, - MMSim *sim, - guint slot_num) -{ - g_return_val_if_fail (CC_IS_WWAN_DEVICE (self), NULL); - - MMSimType simType; - gchar *slot_number; - GString *str, *mmSimType; - - str = g_string_sized_new (5); - simType = mm_sim_get_sim_type (sim); - slot_number = g_strdup_printf ("Slot %d", slot_num); - g_string_append (str, slot_number); - - switch(simType) - { - case MM_SIM_TYPE_UNKNOWN: - mmSimType = g_string_append (str, _(" [Unknown]")); - break; - case MM_SIM_TYPE_PHYSICAL: - mmSimType = g_string_append (str, _(" [Physical]")); - break; - case MM_SIM_TYPE_ESIM: - mmSimType = g_string_append (str, _(" [ESIM]")); - break; - default: - mmSimType = g_string_append (str, _(" [Unknown]")); - break; - } - - return g_string_free (str, FALSE); -} - gchar * cc_wwan_device_get_string_from_mode (CcWwanDevice *self, MMModemMode allowed, diff --git a/panels/wwan/cc-wwan-device.h b/panels/wwan/cc-wwan-device.h index 1835eb7fc7..543350254c 100644 --- a/panels/wwan/cc-wwan-device.h +++ b/panels/wwan/cc-wwan-device.h @@ -43,12 +43,6 @@ typedef enum CC_WWAN_REGISTRATION_STATE_DENIED } CcWwanState; -typedef enum -{ - CC_WWAN_SIM_SLOT_1, - CC_WWAN_SIM_SLOT_2 -} CcWwanSimSlot; - typedef struct _CcWwanData CcWwanData; #define CC_TYPE_WWAN_DEVICE (cc_wwan_device_get_type()) @@ -131,9 +125,6 @@ gboolean cc_wwan_device_set_current_mode_finish (CcWwanDevice *self gchar *cc_wwan_device_get_string_from_mode (CcWwanDevice *self, MMModemMode allowed, MMModemMode preferred); -gchar *cc_wwan_device_get_string_from_slots (CcWwanDevice *self, - MMSim *sim, - guint slot_num); void cc_wwan_device_scan_networks (CcWwanDevice *self, GCancellable *cancellable, GAsyncReadyCallback callback, diff --git a/panels/wwan/cc-wwan-sim-slot-dialog.c b/panels/wwan/cc-wwan-sim-slot-dialog.c deleted file mode 100644 index af2cf22146..0000000000 --- a/panels/wwan/cc-wwan-sim-slot-dialog.c +++ /dev/null @@ -1,235 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* cc-wwan-sim-slot-dialog.c - * - * Copyright (C) 2024 Josef Vincent Ouano - * - * 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 . - * - * Author(s): - * Josef Vincent Ouano - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "cc-network-sim-slot-dialog" - -#include -#include -#include - -#include "cc-wwan-sim-slot-dialog.h" -#include "cc-wwan-sim-slot-row.h" -#include "cc-wwan-resources.h" -#include "cc-wwan-device.h" - -/** - * @short_description: WWAN sim slot selection dialog - */ - -struct _CcWwanSimSlotDialog -{ - AdwDialog parent_instance; - - CcWwanDevice *device; - - AdwPreferencesGroup *sim_slot_list; - CcWwanSimSlotRow *selected_row; - - GCancellable *cancellable; -}; - -G_DEFINE_TYPE (CcWwanSimSlotDialog, cc_wwan_sim_slot_dialog, ADW_TYPE_DIALOG) - -enum { - PROP_0, - PROP_DEVICE, - N_PROPS -}; - -static GParamSpec *properties[N_PROPS]; - -static void -cc_wwan_sim_slot_row_class_init (CcWwanSimSlotRowClass *klass) -{ -} - -static void -cc_wwan_sim_slot_row_init (CcWwanSimSlotRow *row) -{ -} - -static void -cc_wwan_sim_slot_changed_cb (CcWwanSimSlotDialog *self, - CcWwanSimSlotRow *row) -{ - g_assert (CC_IS_WWAN_SIM_SLOT_DIALOG (self)); - - if (row == self->selected_row) - return; - - cc_wwan_sim_slot_row_update_icon (row, TRUE); - - if (self->selected_row) { - cc_wwan_sim_slot_row_update_icon (self->selected_row, FALSE); - } - - self->selected_row = row; -} - -static void -cc_wwan_sim_slot_dialog_ok_clicked_cb (CcWwanSimSlotDialog *self) -{ - g_assert (CC_IS_WWAN_SIM_SLOT_DIALOG (self)); - - if (self->selected_row) - { - cc_wwan_device_set_primary_sim_slot (self->device, cc_wwan_sim_slot_row_get_slot_num (self->selected_row), self->cancellable); - } - else - { - g_return_if_reached (); - } - - adw_dialog_close (ADW_DIALOG (self)); -} - -static CcWwanSimSlotRow * -cc_wwan_sim_slot_dialog_row_new (CcWwanSimSlotDialog *self, MMSim *sim, guint slot_num) -{ - CcWwanSimSlotRow *row; - g_autofree gchar *slot_label = NULL; - - slot_label = cc_wwan_device_get_string_from_slots (self->device, sim, slot_num); - row = cc_wwan_sim_slot_row_new (slot_label, slot_num); - - return row; -} - -static void -cc_wwan_sim_slot_dialog_update (CcWwanSimSlotDialog *self) -{ - GPtrArray *sim_slots; - gboolean simActive = false; - - sim_slots = g_ptr_array_new (); - sim_slots = cc_wwan_device_get_sim_slots (self->device, self->cancellable); - - for (int i = 0; i < sim_slots->len; i++) - { - MMSim *sim; - CcWwanSimSlotRow *row; - - sim = MM_SIM (g_ptr_array_index (sim_slots, i)); - row = cc_wwan_sim_slot_dialog_row_new (self, sim, i+1); - - simActive = mm_sim_get_active (sim); - if (simActive == true) { - cc_wwan_sim_slot_row_update_icon (row, TRUE); - self->selected_row = row; - } - else if (simActive == false) { - cc_wwan_sim_slot_row_update_icon (row, FALSE); - } - - g_signal_connect_swapped (G_OBJECT (row), "activated", G_CALLBACK (cc_wwan_sim_slot_changed_cb), self); - adw_preferences_group_add (self->sim_slot_list, GTK_WIDGET (row)); - } -} - -static void -cc_wwan_sim_slot_dialog_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - CcWwanSimSlotDialog *self = (CcWwanSimSlotDialog *)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_slot_dialog_constructed (GObject *object) -{ - CcWwanSimSlotDialog *self = CC_WWAN_SIM_SLOT_DIALOG (object); - - G_OBJECT_CLASS (cc_wwan_sim_slot_dialog_parent_class)->constructed (object); - cc_wwan_sim_slot_dialog_update (self); -} - -static void -cc_wwan_sim_slot_dialog_dispose (GObject *object) -{ - CcWwanSimSlotDialog *self = CC_WWAN_SIM_SLOT_DIALOG (object); - - g_cancellable_cancel (self->cancellable); - g_clear_object (&self->device); - - G_OBJECT_CLASS (cc_wwan_sim_slot_dialog_parent_class)->dispose (object); -} - -static void -cc_wwan_sim_slot_dialog_class_init (CcWwanSimSlotDialogClass *klass) -{ - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = cc_wwan_sim_slot_dialog_set_property; - object_class->constructed = cc_wwan_sim_slot_dialog_constructed; - object_class->dispose = cc_wwan_sim_slot_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-sim-slot-dialog.ui"); - - gtk_widget_class_bind_template_child (widget_class, CcWwanSimSlotDialog, sim_slot_list); - - gtk_widget_class_bind_template_callback (widget_class, cc_wwan_sim_slot_dialog_ok_clicked_cb); -} - -static void -cc_wwan_sim_slot_dialog_init (CcWwanSimSlotDialog *self) -{ - gtk_widget_init_template (GTK_WIDGET (self)); - - self->cancellable = g_cancellable_new (); -} - -GtkWidget * -cc_wwan_sim_slot_dialog_new (GtkBox *parent_window, - CcWwanDevice *device) -{ - CcWwanSimSlotDialog *self; - - self = g_object_new (CC_TYPE_WWAN_SIM_SLOT_DIALOG, - "device", device, - NULL); - return GTK_WIDGET (self); -} diff --git a/panels/wwan/cc-wwan-sim-slot-dialog.h b/panels/wwan/cc-wwan-sim-slot-dialog.h deleted file mode 100644 index 173e86d274..0000000000 --- a/panels/wwan/cc-wwan-sim-slot-dialog.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* cc-wwan-sim-slot-dialog.h - * - * Copyright (C) 2024 Josef Vincent Ouano - * - * 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 . - * - * Author(s): - * Josef Vincent Ouano - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include -#include - -#include "cc-wwan-device.h" - -G_BEGIN_DECLS - -#define CC_TYPE_WWAN_SIM_SLOT_DIALOG (cc_wwan_sim_slot_dialog_get_type()) -G_DECLARE_FINAL_TYPE (CcWwanSimSlotDialog, cc_wwan_sim_slot_dialog, CC, WWAN_SIM_SLOT_DIALOG, AdwDialog) - -GtkWidget *cc_wwan_sim_slot_dialog_new (GtkBox *parent_window, - CcWwanDevice *device); - -G_END_DECLS \ No newline at end of file diff --git a/panels/wwan/cc-wwan-sim-slot-dialog.ui b/panels/wwan/cc-wwan-sim-slot-dialog.ui deleted file mode 100644 index 0fb7d50b49..0000000000 --- a/panels/wwan/cc-wwan-sim-slot-dialog.ui +++ /dev/null @@ -1,52 +0,0 @@ - - - - - diff --git a/panels/wwan/cc-wwan-sim-slot-row.c b/panels/wwan/cc-wwan-sim-slot-row.c deleted file mode 100644 index 3e3ef84ff6..0000000000 --- a/panels/wwan/cc-wwan-sim-slot-row.c +++ /dev/null @@ -1,90 +0,0 @@ -/* cc-applications-row.c - * - * Copyright 2024 Josef Vincent Ouano - * - * 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 . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include -#include - -#include "cc-wwan-sim-slot-row.h" - -struct _CcWwanSimSlotRow -{ - AdwActionRow parent_instance; - GtkImage *ok_emblem; - guint slot_num; -}; - -G_DEFINE_TYPE (CcWwanSimSlotRow, cc_wwan_sim_slot_row, ADW_TYPE_ACTION_ROW) - -static void -cc_wwan_sim_slot_row_finalize (GObject *object) -{ - CcWwanSimSlotRow *self = CC_WWAN_SIM_SLOT_ROW (object); - G_OBJECT_CLASS (cc_wwan_sim_slot_row_parent_class)->finalize (object); -} - -static void -cc_wwan_sim_slot_row_class_init (CcWwanSimSlotRowClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->finalize = cc_wwan_sim_slot_row_finalize; -} - -static void -cc_wwan_sim_slot_row_init (CcWwanSimSlotRow *self) -{ - gtk_widget_init_template (GTK_WIDGET (self)); -} - -void -cc_wwan_sim_slot_row_update_icon (CcWwanSimSlotRow *self, gboolean isEnabled) -{ - g_return_if_fail (CC_IS_WWAN_SIM_SLOT_ROW (self)); - - gtk_widget_set_visible (GTK_WIDGET (self->ok_emblem), isEnabled); -} - -guint -cc_wwan_sim_slot_row_get_slot_num (CcWwanSimSlotRow *self) -{ - return self->slot_num; -} - -CcWwanSimSlotRow * -cc_wwan_sim_slot_row_new (gchar *slot_label, guint slot_num) -{ - CcWwanSimSlotRow *self; - GtkWidget *box, *image; - - self = g_object_new (CC_TYPE_WWAN_SIM_SLOT_ROW, NULL); - self->slot_num = slot_num; - - adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), slot_label); - - image = gtk_image_new_from_icon_name ("emblem-ok-symbolic"); - self->ok_emblem = GTK_IMAGE (image); - adw_action_row_add_suffix (ADW_ACTION_ROW (self), GTK_WIDGET (self->ok_emblem)); - - box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); - adw_action_row_set_activatable_widget (ADW_ACTION_ROW (self), box); - - return self; -} diff --git a/panels/wwan/cc-wwan-sim-slot-row.h b/panels/wwan/cc-wwan-sim-slot-row.h deleted file mode 100644 index 6c3043cca1..0000000000 --- a/panels/wwan/cc-wwan-sim-slot-row.h +++ /dev/null @@ -1,37 +0,0 @@ -/* cc-wwan-sim-slot-row.h - * - * Copyright 2024 Josef Vincent Ouano - * - * 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 . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include -#include - -G_BEGIN_DECLS - -#define CC_TYPE_WWAN_SIM_SLOT_ROW (cc_wwan_sim_slot_row_get_type()) -G_DECLARE_FINAL_TYPE (CcWwanSimSlotRow, cc_wwan_sim_slot_row, CC, WWAN_SIM_SLOT_ROW, AdwActionRow) - -CcWwanSimSlotRow* cc_wwan_sim_slot_row_new (gchar *slot_label, guint slot_num); - -void cc_wwan_sim_slot_row_update_icon (CcWwanSimSlotRow *self, gboolean isEnabled); - -guint cc_wwan_sim_slot_row_get_slot_num (CcWwanSimSlotRow *self); - -G_END_DECLS \ No newline at end of file diff --git a/panels/wwan/meson.build b/panels/wwan/meson.build index 1a35710ba3..cbadae59de 100644 --- a/panels/wwan/meson.build +++ b/panels/wwan/meson.build @@ -43,8 +43,6 @@ sources = files( 'cc-wwan-details-dialog.c', 'cc-wwan-sim-lock-dialog.c', 'cc-wwan-apn-dialog.c', - 'cc-wwan-sim-slot-dialog.c', - 'cc-wwan-sim-slot-row.c', ) sources += gnome.compile_resources( diff --git a/panels/wwan/wwan.gresource.xml b/panels/wwan/wwan.gresource.xml index d2ed89a76f..f128a164a4 100644 --- a/panels/wwan/wwan.gresource.xml +++ b/panels/wwan/wwan.gresource.xml @@ -8,6 +8,5 @@ cc-wwan-details-dialog.ui cc-wwan-sim-lock-dialog.ui cc-wwan-apn-dialog.ui - cc-wwan-sim-slot-dialog.ui -- GitLab From d0e96af52e69dc0724b98a085352a75cb25b9541 Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Mon, 25 Aug 2025 14:40:38 +0200 Subject: [PATCH 3/9] wwan: Don't select primary slot on panel startup By connecting to the combo selected property in the ui file we end up calling the callback at startup. We only want it called when the user explicitly chooses an option in the combo row --- panels/wwan/cc-wwan-device-page.blp | 1 - panels/wwan/cc-wwan-device-page.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panels/wwan/cc-wwan-device-page.blp b/panels/wwan/cc-wwan-device-page.blp index bb8964c5bb..1fe297cab1 100644 --- a/panels/wwan/cc-wwan-device-page.blp +++ b/panels/wwan/cc-wwan-device-page.blp @@ -126,7 +126,6 @@ template $CcWwanDevicePage: Box { Adw.ComboRow sim_slot_row { use-underline: true; title: _("Primary S_IM Slot"); - notify::selected => $wwan_device_set_primary_sim_slot_cb(template); model: StringList sim_slot_string_list {}; } diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c index 0deaed08c7..b81ced39f4 100644 --- a/panels/wwan/cc-wwan-device-page.c +++ b/panels/wwan/cc-wwan-device-page.c @@ -573,6 +573,8 @@ cc_wwan_device_page_constructed (GObject *object) cc_wwan_device_page_update (self); cc_wwan_locks_changed_cb (self); cc_wwan_update_sim_slots_row (self); + + g_signal_connect_swapped (self->sim_slot_row, "notify::selected", (GCallback)wwan_device_set_primary_sim_slot_cb, self); } static void @@ -632,7 +634,6 @@ cc_wwan_device_page_class_init (CcWwanDevicePageClass *klass) 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_device_set_primary_sim_slot_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); -- GitLab From 2d510f2f3b470a571f9f1960a17c966c4173e907 Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Wed, 14 Jan 2026 11:29:01 +0100 Subject: [PATCH 4/9] polkit: Add rule for setting primary sim slot in wwan modems https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/blob/089d0e3353e3b62af7f13b86aec0bb26fb5cb02a/data/org.freedesktop.ModemManager1.policy.in.in#L30 --- 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 22cf785e09..8532d1e33c 100644 --- a/panels/common/gnome-control-center.rules.in +++ b/panels/common/gnome-control-center.rules.in @@ -2,6 +2,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.ModemManager1.Modem.SetPrimarySimSlot" || action.id == "org.freedesktop.hostname1.set-static-hostname" || action.id == "org.freedesktop.hostname1.set-hostname" || action.id == "org.gnome.controlcenter.datetime.configure") && -- GitLab From a886242e3a708f072c9512416cc18169867b2840 Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Wed, 14 Jan 2026 11:29:26 +0100 Subject: [PATCH 5/9] wwan, device-page: Make sure we handle when a sim card slot is empty mm_modem_list_sim_slots() returns an array containing one item for each slot available in the modem. When the slot doesn't have a valid SIM card, NULL is added to the array as a placeholder. --- panels/wwan/cc-wwan-device-page.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c index b81ced39f4..67629816d6 100644 --- a/panels/wwan/cc-wwan-device-page.c +++ b/panels/wwan/cc-wwan-device-page.c @@ -504,24 +504,33 @@ cc_wwan_update_sim_slots_row (CcWwanDevicePage *self) gtk_widget_set_visible (GTK_WIDGET (self->sim_slot_row), sim_slots->len > 0); for (i = 0; i < sim_slots->len; i++) { - MMSim *sim = MM_SIM (g_ptr_array_index (sim_slots, i)); - MMSimType sim_type = mm_sim_get_sim_type (sim); + MMSim *sim = g_ptr_array_index (sim_slots, i); g_autofree gchar *sim_type_label = NULL; g_autofree gchar *sim_label = NULL; - if (sim_type == MM_SIM_TYPE_PHYSICAL) - sim_type_label = g_strdup_printf ("[%s]", _("Physical")); - else if (sim_type == MM_SIM_TYPE_ESIM) - sim_type_label = g_strdup ("[ESIM]"); /* Let's not translate ESIM. */ + /* Empty slot - no SIM card inserted */ + if (sim == NULL) + { + sim_type_label = g_strdup_printf ("[%s]", _("Empty")); + } else - sim_type_label = g_strdup_printf ("[%s]", _("Unknown")); + { + MMSimType sim_type = mm_sim_get_sim_type (sim); + + if (sim_type == MM_SIM_TYPE_PHYSICAL) + sim_type_label = g_strdup_printf ("[%s]", _("Physical")); + else if (sim_type == MM_SIM_TYPE_ESIM) + sim_type_label = g_strdup ("[eSIM]"); /* Let's not translate eSIM. */ + else + sim_type_label = g_strdup_printf ("[%s]", _("Unknown")); + } /* Translators: This refers to a physical or esim slot in a modem. * For example: "Slot 1 Physical" or "Slot 2 ESIM". */ sim_label = g_strdup_printf (_("Slot %d %s"), i+1, sim_type_label); gtk_string_list_append (self->sim_slot_string_list, sim_label); - if (mm_sim_get_active (sim)) + if (sim != NULL && mm_sim_get_active (sim)) adw_combo_row_set_selected (self->sim_slot_row, i); } } -- GitLab From de18d12f38e6a72144de54cae5e305738edcabd4 Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Wed, 14 Jan 2026 15:39:29 +0100 Subject: [PATCH 6/9] wwan, device: Use MMModem to query for primary sim slot We were wrongly relying on the mm_sim_get_active() state to determine whether a slot is the primary. A slot can be set as primary while not having an active or valid SIM card. --- panels/wwan/cc-wwan-device-page.c | 8 ++++---- panels/wwan/cc-wwan-device.c | 6 ++++++ panels/wwan/cc-wwan-device.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c index 67629816d6..420f383c18 100644 --- a/panels/wwan/cc-wwan-device-page.c +++ b/panels/wwan/cc-wwan-device-page.c @@ -490,7 +490,7 @@ wwan_device_set_primary_sim_slot_cb (CcWwanDevicePage *self) { guint primary_slot = adw_combo_row_get_selected (self->sim_slot_row); - cc_wwan_device_set_primary_sim_slot (self->device, primary_slot, NULL); // FIXME: cancellable + cc_wwan_device_set_primary_sim_slot (self->device, primary_slot + 1, NULL); // FIXME: cancellable g_debug ("Setting primary sim slot to %d", primary_slot); } @@ -529,10 +529,10 @@ cc_wwan_update_sim_slots_row (CcWwanDevicePage *self) * For example: "Slot 1 Physical" or "Slot 2 ESIM". */ sim_label = g_strdup_printf (_("Slot %d %s"), i+1, sim_type_label); gtk_string_list_append (self->sim_slot_string_list, sim_label); - - if (sim != NULL && mm_sim_get_active (sim)) - adw_combo_row_set_selected (self->sim_slot_row, i); } + + adw_combo_row_set_selected (self->sim_slot_row, + cc_wwan_device_get_primary_sim_slot (self->device) - 1); } static void diff --git a/panels/wwan/cc-wwan-device.c b/panels/wwan/cc-wwan-device.c index 1debe41c37..e04433e1c7 100644 --- a/panels/wwan/cc-wwan-device.c +++ b/panels/wwan/cc-wwan-device.c @@ -101,6 +101,12 @@ cc_wwan_device_set_primary_sim_slot (CcWwanDevice *self, guint sim_slot, GCancel g_warning ("Error:%s", error->message); } +guint +cc_wwan_device_get_primary_sim_slot (CcWwanDevice *self) +{ + return mm_modem_get_primary_sim_slot (self->modem); +} + GPtrArray * cc_wwan_device_get_sim_slots (CcWwanDevice *self, GCancellable *cancellable) { diff --git a/panels/wwan/cc-wwan-device.h b/panels/wwan/cc-wwan-device.h index 543350254c..938cb70f23 100644 --- a/panels/wwan/cc-wwan-device.h +++ b/panels/wwan/cc-wwan-device.h @@ -153,5 +153,6 @@ GPtrArray *cc_wwan_device_get_sim_slots (CcWwanDevice *self void cc_wwan_device_set_primary_sim_slot (CcWwanDevice *self, guint sim_slot, GCancellable *cancellable); +guint cc_wwan_device_get_primary_sim_slot (CcWwanDevice *self); G_END_DECLS -- GitLab From a9b0e5d0e9b3eb8a92e05ea74647f922806e786d Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Thu, 15 Jan 2026 12:21:08 +0100 Subject: [PATCH 7/9] wwan: Don't hide panel when reprobing devices Whe we use mm_modem_set_primary_sim_slot(), ModemManager triggers a full device reprobe. This way, the modem object in DBus gets removed and recreated once the selected SIM slot is in use. Let's show a "Loading Devices" page while we wait to repopulate the panel when the newly created ModemManager devices appear in DBus. See also https://www.freedesktop.org/software/ModemManager/api/latest/gdbus-org.freedesktop.ModemManager1.Modem.html#gdbus-method-org-freedesktop-ModemManager1-Modem.SetPrimarySimSlot Let's still hide the panel when no devices are available when Settings starts up. --- panels/wwan/cc-wwan-panel.blp | 9 +++++++++ panels/wwan/cc-wwan-panel.c | 7 ++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/panels/wwan/cc-wwan-panel.blp b/panels/wwan/cc-wwan-panel.blp index edff62d4f1..14a5c6fb26 100644 --- a/panels/wwan/cc-wwan-panel.blp +++ b/panels/wwan/cc-wwan-panel.blp @@ -67,6 +67,15 @@ template $CcWwanPanel: $CcPanel { }; } + StackPage { + name: "loading-page"; + + child: Adw.StatusPage { + title: _("Loading Devices"); + child: Adw.Spinner {}; + }; + } + StackPage { name: "device-settings"; diff --git a/panels/wwan/cc-wwan-panel.c b/panels/wwan/cc-wwan-panel.c index 3ba2bc46cb..bee916ee93 100644 --- a/panels/wwan/cc-wwan-panel.c +++ b/panels/wwan/cc-wwan-panel.c @@ -370,6 +370,8 @@ cc_wwan_panel_add_device (CcWwanPanel *self, 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); + + gtk_stack_set_visible_child_name (self->main_stack, "device-settings"); } static void @@ -560,6 +562,8 @@ wwan_panel_device_removed_cb (CcWwanPanel *self, gtk_revealer_set_reveal_child (self->multi_device_revealer, g_list_model_get_n_items (G_LIST_MODEL (self->devices)) > 1); + + gtk_stack_set_visible_child_name (self->main_stack, "loading-page"); } static GPtrArray * @@ -830,8 +834,5 @@ cc_wwan_panel_static_init_func (void) 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); } -- GitLab From 997cc170d3ec9e34879f074ba695a1d4192731a4 Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Sat, 17 Jan 2026 13:29:38 +0100 Subject: [PATCH 8/9] wwan, device: Show "Slot 1 [Operator Name]" to identify sim slots We can't reliably identify whether the slots are eSIM or physical, and when there are two slots of the same time. Also, we can't differentiate easily "Slot 1" from "Slot 2". So let's use the SIM operator name (when available) to differentiate. --- panels/wwan/cc-wwan-device-page.c | 34 ++++++++++++++----------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c index 420f383c18..2d9a55667e 100644 --- a/panels/wwan/cc-wwan-device-page.c +++ b/panels/wwan/cc-wwan-device-page.c @@ -505,29 +505,25 @@ cc_wwan_update_sim_slots_row (CcWwanDevicePage *self) for (i = 0; i < sim_slots->len; i++) { MMSim *sim = g_ptr_array_index (sim_slots, i); - g_autofree gchar *sim_type_label = NULL; + g_autofree gchar *slot_state = NULL; g_autofree gchar *sim_label = NULL; /* Empty slot - no SIM card inserted */ if (sim == NULL) - { - sim_type_label = g_strdup_printf ("[%s]", _("Empty")); - } - else - { - MMSimType sim_type = mm_sim_get_sim_type (sim); - - if (sim_type == MM_SIM_TYPE_PHYSICAL) - sim_type_label = g_strdup_printf ("[%s]", _("Physical")); - else if (sim_type == MM_SIM_TYPE_ESIM) - sim_type_label = g_strdup ("[eSIM]"); /* Let's not translate eSIM. */ - else - sim_type_label = g_strdup_printf ("[%s]", _("Unknown")); - } - - /* Translators: This refers to a physical or esim slot in a modem. - * For example: "Slot 1 Physical" or "Slot 2 ESIM". */ - sim_label = g_strdup_printf (_("Slot %d %s"), i+1, sim_type_label); + slot_state = g_strdup_printf ("[%s]", _("Empty")); + else { + const gchar *operator_name = mm_sim_get_operator_name (sim); + if (operator_name) + slot_state = g_strdup_printf ("[%s]", operator_name); + else + slot_state = g_strdup (""); + } + + /* Translators: This refers to a sim slot in a modem. + * For example: "Slot 1 [Operator Name]", "Slot 1" or "Slot 2 [Empty]". + * Notice that all variations above are valid. Sometimes "Operator Name" + * will be ommitted.*/ + sim_label = g_strdup_printf (_("Slot %d %s"), i+1, slot_state); gtk_string_list_append (self->sim_slot_string_list, sim_label); } -- GitLab From 9627d5b3dc4b54d3f89ab40b3dd6a540bea043b0 Mon Sep 17 00:00:00 2001 From: Felipe Borges Date: Fri, 6 Feb 2026 12:26:52 +0100 Subject: [PATCH 9/9] wwan, device-page: Make device-page calls cancellable --- panels/wwan/cc-wwan-device-page.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/panels/wwan/cc-wwan-device-page.c b/panels/wwan/cc-wwan-device-page.c index 2d9a55667e..6fbbc6f767 100644 --- a/panels/wwan/cc-wwan-device-page.c +++ b/panels/wwan/cc-wwan-device-page.c @@ -79,6 +79,7 @@ struct _CcWwanDevicePage CcWwanDevice *device; CcWwanData *wwan_data; GDBusProxy *wwan_proxy; + GCancellable *cancellable; GtkWindow *apn_dialog; GtkWindow *network_mode_dialog; @@ -128,7 +129,7 @@ wwan_device_page_handle_data_row (CcWwanDevicePage *self, else cc_wwan_data_set_roaming_enabled (self->wwan_data, active); - cc_wwan_data_save_settings (self->wwan_data, NULL, NULL, NULL); + cc_wwan_data_save_settings (self->wwan_data, self->cancellable, NULL, NULL); } static gboolean @@ -177,7 +178,7 @@ cc_wwan_device_page_new_prompt (CcWwanDevicePage *self, const gchar *message = NULL; guint num; - prompt = GCR_PROMPT (gcr_system_prompt_open (-1, NULL, &error)); + prompt = GCR_PROMPT (gcr_system_prompt_open (-1, self->cancellable, &error)); if (error) { @@ -271,7 +272,7 @@ wwan_device_unlock_clicked_cb (CcWwanDevicePage *self) 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); + password = gcr_prompt_password (prompt, self->cancellable, &error); gcr_prompt_set_warning (prompt, warning); } @@ -299,7 +300,7 @@ wwan_device_unlock_clicked_cb (CcWwanDevicePage *self) 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); + password = gcr_prompt_password (prompt, self->cancellable, &error); gcr_prompt_set_warning (prompt, warning); } @@ -319,13 +320,13 @@ wwan_device_unlock_clicked_cb (CcWwanDevicePage *self) if (lock == MM_MODEM_LOCK_SIM_PIN) cc_wwan_device_send_pin (self->device, pin, - NULL, /* cancellable */ + self->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 */ + self->cancellable, cc_wwan_device_page_unlocked_cb, self); } @@ -490,14 +491,14 @@ wwan_device_set_primary_sim_slot_cb (CcWwanDevicePage *self) { guint primary_slot = adw_combo_row_get_selected (self->sim_slot_row); - cc_wwan_device_set_primary_sim_slot (self->device, primary_slot + 1, NULL); // FIXME: cancellable + cc_wwan_device_set_primary_sim_slot (self->device, primary_slot + 1, self->cancellable); g_debug ("Setting primary sim slot to %d", primary_slot); } static void cc_wwan_update_sim_slots_row (CcWwanDevicePage *self) { - g_autoptr(GPtrArray) sim_slots = cc_wwan_device_get_sim_slots (self->device, NULL); // FIXME: cancellable + g_autoptr(GPtrArray) sim_slots = cc_wwan_device_get_sim_slots (self->device, self->cancellable); int i; /* There's nothing the user can do if we get zero slots. Hide the row. */ @@ -593,6 +594,9 @@ cc_wwan_device_page_dispose (GObject *object) g_clear_pointer (&self->sim_lock_dialog, gtk_window_destroy); g_clear_pointer (&self->sim_slot_dialog, gtk_window_destroy); + g_cancellable_cancel (self->cancellable); + + g_clear_object (&self->cancellable); g_clear_object (&self->wwan_proxy); g_clear_object (&self->device); @@ -648,6 +652,8 @@ static void cc_wwan_device_page_init (CcWwanDevicePage *self) { gtk_widget_init_template (GTK_WIDGET (self)); + + self->cancellable = g_cancellable_new (); } static void -- GitLab