GCC Code Coverage Report


Directory: ./
File: panels/wwan/cc-wwan-panel.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 353 0.0%
Functions: 0 36 0.0%
Branches: 0 220 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* cc-wwan-panel.c
3 *
4 * Copyright 2019,2022 Purism SPC
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author(s):
20 * Mohammed Sadiq <sadiq@sadiqpk.org>
21 *
22 * SPDX-License-Identifier: GPL-3.0-or-later
23 */
24
25 #undef G_LOG_DOMAIN
26 #define G_LOG_DOMAIN "cc-wwan-panel"
27
28 #include <config.h>
29 #include <glib/gi18n.h>
30 #include <libmm-glib.h>
31
32 #include "cc-wwan-device.h"
33 #include "cc-wwan-data.h"
34 #include "cc-wwan-device-page.h"
35 #include "cc-wwan-panel.h"
36 #include "cc-wwan-resources.h"
37
38 #include "shell/cc-application.h"
39 #include "shell/cc-log.h"
40 #include "shell/cc-object-storage.h"
41
42 typedef enum {
43 OPERATION_NULL,
44 OPERATION_SHOW_DEVICE,
45 } CmdlineOperation;
46
47 struct _CcWwanPanel
48 {
49 CcPanel parent_instance;
50
51 AdwToastOverlay *toast_overlay;
52 AdwComboRow *data_list_row;
53 GtkListBox *data_sim_select_listbox;
54 GtkStack *devices_stack;
55 GtkStackSwitcher *devices_switcher;
56 GtkSwitch *enable_switch;
57 GtkStack *main_stack;
58 GtkRevealer *multi_device_revealer;
59
60 GDBusProxy *rfkill_proxy;
61 MMManager *mm_manager;
62 NMClient *nm_client;
63
64 /* The default device that will be used for data */
65 CcWwanDevice *data_device;
66 GListStore *devices;
67 GListStore *data_devices;
68 GListStore *data_devices_name_list;
69 GCancellable *cancellable;
70
71 CmdlineOperation arg_operation;
72 char *arg_device;
73 };
74
75 enum {
76 PROP_0,
77 PROP_PARAMETERS
78 };
79
80 G_DEFINE_TYPE (CcWwanPanel, cc_wwan_panel, CC_TYPE_PANEL)
81
82
83 #define CC_TYPE_DATA_DEVICE_ROW (cc_data_device_row_get_type())
84 G_DECLARE_FINAL_TYPE (CcDataDeviceRow, cc_data_device_row, CC, DATA_DEVICE_ROW, GtkListBoxRow)
85
86 struct _CcDataDeviceRow
87 {
88 GtkListBoxRow parent_instance;
89
90 GtkImage *ok_emblem;
91 CcWwanDevice *device;
92 };
93
94 G_DEFINE_TYPE (CcDataDeviceRow, cc_data_device_row, GTK_TYPE_LIST_BOX_ROW)
95
96 static void
97 cc_data_device_row_class_init (CcDataDeviceRowClass *klass)
98 {
99 }
100
101 static void
102 cc_data_device_row_init (CcDataDeviceRow *row)
103 {
104 }
105
106 static CmdlineOperation
107 cmdline_operation_from_string (const gchar *str)
108 {
109 if (g_strcmp0 (str, "show-device") == 0)
110 return OPERATION_SHOW_DEVICE;
111
112 g_warning ("Invalid additional argument %s", str);
113 return OPERATION_NULL;
114 }
115
116 static void
117 reset_command_line_args (CcWwanPanel *self)
118 {
119 self->arg_operation = OPERATION_NULL;
120 g_clear_pointer (&self->arg_device, g_free);
121 }
122
123 static gboolean
124 verify_argv (CcWwanPanel *self,
125 const char **args)
126 {
127 switch (self->arg_operation)
128 {
129 case OPERATION_SHOW_DEVICE:
130 if (self->arg_device == NULL)
131 {
132 g_warning ("Operation %s requires an object path", args[0]);
133 return FALSE;
134 }
135 default:
136 return TRUE;
137 }
138 }
139
140 static void
141 handle_argv (CcWwanPanel *self)
142 {
143 if (self->arg_operation == OPERATION_SHOW_DEVICE &&
144 self->arg_operation)
145 {
146 for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self->devices_stack));
147 child;
148 child = gtk_widget_get_next_sibling (child))
149 {
150 CcWwanDevice *device;
151
152 device = cc_wwan_device_page_get_device (CC_WWAN_DEVICE_PAGE (child));
153
154 if (g_strcmp0 (cc_wwan_device_get_path (device), self->arg_device) == 0)
155 {
156 gtk_stack_set_visible_child (GTK_STACK (self->devices_stack), child);
157 g_debug ("Opening device %s", self->arg_device);
158 reset_command_line_args (self);
159 return;
160 }
161 }
162 }
163 }
164
165 static gboolean
166 wwan_panel_device_is_supported (GDBusObject *object)
167 {
168 MMObject *mm_object;
169 MMModem *modem;
170 MMModemCapability capability;
171
172 g_assert (G_IS_DBUS_OBJECT (object));
173
174 mm_object = MM_OBJECT (object);
175 modem = mm_object_get_modem (mm_object);
176 capability = mm_modem_get_current_capabilities (modem);
177
178 /* We Support only GSM/3G/LTE devices */
179 if (capability & (MM_MODEM_CAPABILITY_GSM_UMTS |
180 MM_MODEM_CAPABILITY_LTE |
181 MM_MODEM_CAPABILITY_LTE_ADVANCED))
182 return TRUE;
183
184 return FALSE;
185 }
186
187 static gint
188 wwan_model_get_item_index (GListModel *model,
189 gpointer item)
190 {
191 guint i, n_items;
192
193 g_assert (G_IS_LIST_MODEL (model));
194 g_assert (G_IS_OBJECT (item));
195
196 n_items = g_list_model_get_n_items (model);
197
198 for (i = 0; i < n_items; i++)
199 {
200 g_autoptr(GObject) object = NULL;
201
202 object = g_list_model_get_item (model, i);
203
204 if (object == item)
205 return i;
206 }
207
208 return -1;
209 }
210
211 static CcWwanDevice *
212 wwan_model_get_item_from_mm_object (GListModel *model,
213 MMObject *mm_object)
214 {
215 const gchar *modem_path, *device_path;
216 guint i, n_items;
217
218 n_items = g_list_model_get_n_items (model);
219 modem_path = mm_object_get_path (mm_object);
220
221 for (i = 0; i < n_items; i++)
222 {
223 g_autoptr(CcWwanDevice) device = NULL;
224
225 device = g_list_model_get_item (model, i);
226 device_path = cc_wwan_device_get_path (device);
227
228 if (g_str_equal (modem_path, device_path))
229 return g_steal_pointer (&device);
230 }
231
232 return NULL;
233 }
234
235 static void
236 cc_wwan_panel_update_data_selection (CcWwanPanel *self)
237 {
238 int i;
239
240 if (!self->data_device)
241 return;
242
243 i = wwan_model_get_item_index (G_LIST_MODEL (self->data_devices), self->data_device);
244
245 if (i != -1)
246 adw_combo_row_set_selected (self->data_list_row, i);
247 }
248
249 static void
250 cc_wwan_data_item_activate_cb (CcWwanPanel *self,
251 CcWwanDevice *device)
252 {
253 CcWwanData *data;
254
255 if (device == self->data_device)
256 return;
257
258 if (!self->data_device)
259 return;
260
261 /* Set lower priority for previously selected APN */
262 data = cc_wwan_device_get_data (self->data_device);
263 cc_wwan_data_set_priority (data, CC_WWAN_APN_PRIORITY_LOW);
264 cc_wwan_data_save_settings (data, NULL, NULL, NULL);
265
266 /* Set high priority for currently selected APN */
267 data = cc_wwan_device_get_data (device);
268 cc_wwan_data_set_priority (data, CC_WWAN_APN_PRIORITY_HIGH);
269 cc_wwan_data_save_settings (data, NULL, NULL, NULL);
270
271 self->data_device = device;
272 cc_wwan_panel_update_data_selection (self);
273 }
274
275 static void
276 wwan_on_airplane_off_clicked_cb (CcWwanPanel *self)
277 {
278 g_debug ("Airplane Mode Off clicked, disabling airplane mode");
279 g_dbus_proxy_call (self->rfkill_proxy,
280 "org.freedesktop.DBus.Properties.Set",
281 g_variant_new_parsed ("('org.gnome.SettingsDaemon.Rfkill',"
282 "'AirplaneMode', %v)",
283 g_variant_new_boolean (FALSE)),
284 G_DBUS_CALL_FLAGS_NONE,
285 -1,
286 self->cancellable,
287 NULL,
288 NULL);
289 }
290
291 static void
292 wwan_data_list_selected_sim_changed_cb (CcWwanPanel *self)
293 {
294 CcWwanDevice *device;
295 GObject *selected;
296
297 g_assert (CC_IS_WWAN_PANEL (self));
298
299 selected = adw_combo_row_get_selected_item (self->data_list_row);
300 if (!selected)
301 return;
302
303 device = g_object_get_data (selected, "device");
304 cc_wwan_data_item_activate_cb (self, device);
305 }
306
307 static gboolean
308 cc_wwan_panel_get_cached_dbus_property (GDBusProxy *proxy,
309 const gchar *property)
310 {
311 g_autoptr(GVariant) result = NULL;
312
313 g_assert (G_IS_DBUS_PROXY (proxy));
314 g_assert (property && *property);
315
316 result = g_dbus_proxy_get_cached_property (proxy, property);
317 g_assert (!result || g_variant_is_of_type (result, G_VARIANT_TYPE_BOOLEAN));
318
319 return result ? g_variant_get_boolean (result) : FALSE;
320 }
321
322 static void
323 cc_wwan_panel_update_view (CcWwanPanel *self)
324 {
325 gboolean has_airplane, is_airplane = FALSE, enabled = FALSE;
326
327 has_airplane = cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "HasAirplaneMode");
328 has_airplane &= cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "ShouldShowAirplaneMode");
329
330 if (has_airplane)
331 {
332 is_airplane = cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "AirplaneMode");
333 is_airplane |= cc_wwan_panel_get_cached_dbus_property (self->rfkill_proxy, "HardwareAirplaneMode");
334 }
335
336 if (self->nm_client)
337 enabled = nm_client_wwan_get_enabled (self->nm_client);
338
339 if (has_airplane && is_airplane)
340 gtk_stack_set_visible_child_name (self->main_stack, "airplane-mode");
341 else if (enabled && g_list_model_get_n_items (G_LIST_MODEL (self->devices)) > 0)
342 gtk_stack_set_visible_child_name (self->main_stack, "device-settings");
343 else
344 gtk_stack_set_visible_child_name (self->main_stack, "no-wwan-devices");
345
346 gtk_widget_set_sensitive (GTK_WIDGET (self->enable_switch), !is_airplane);
347
348 if (enabled)
349 gtk_revealer_set_reveal_child (self->multi_device_revealer,
350 g_list_model_get_n_items (G_LIST_MODEL (self->devices)) > 1);
351 }
352
353 static void
354 cc_wwan_panel_add_device (CcWwanPanel *self,
355 CcWwanDevice *device)
356 {
357 CcWwanDevicePage *device_page;
358 g_autofree gchar *operator_name = NULL;
359 g_autofree gchar *stack_name = NULL;
360 guint n_items;
361
362 g_list_store_append (self->devices, device);
363
364 n_items = g_list_model_get_n_items (G_LIST_MODEL (self->devices));
365 operator_name = g_strdup_printf (_("SIM %d"), n_items);
366 stack_name = g_strdup_printf ("sim-%d", n_items);
367
368 device_page = cc_wwan_device_page_new (device, GTK_WIDGET (self->toast_overlay));
369 cc_wwan_device_page_set_sim_index (device_page, n_items);
370 gtk_stack_add_titled (self->devices_stack,
371 GTK_WIDGET (device_page), stack_name, operator_name);
372 }
373
374 static void
375 cc_wwan_panel_update_page_title (CcWwanDevicePage *device_page,
376 CcWwanPanel *self)
377 {
378 g_autofree gchar *title = NULL;
379 g_autofree gchar *name = NULL;
380 CcWwanDevice *device;
381 GtkStackPage *page;
382 gint index;
383
384 g_assert (CC_IS_WWAN_DEVICE_PAGE (device_page));
385
386 device = cc_wwan_device_page_get_device (device_page);
387
388 page = gtk_stack_get_page (GTK_STACK (self->devices_stack), GTK_WIDGET (device_page));
389 index = wwan_model_get_item_index (G_LIST_MODEL (self->devices), device);
390
391 if (index == -1)
392 g_return_if_reached ();
393
394 /* index starts with 0, but we need human readable index to be 1+ */
395 cc_wwan_device_page_set_sim_index (device_page, index + 1);
396 title = g_strdup_printf (_("SIM %d"), index + 1);
397 name = g_strdup_printf ("sim-%d", index + 1);
398 gtk_stack_page_set_title (page, title);
399 gtk_stack_page_set_name (page, name);
400 }
401
402 static void
403 cc_wwan_panel_remove_mm_object (CcWwanPanel *self,
404 MMObject *mm_object)
405 {
406 g_autoptr(CcWwanDevice) device = NULL;
407 GtkWidget *device_page;
408 g_autofree gchar *stack_name = NULL;
409 guint n_items;
410 gint index;
411
412 device = wwan_model_get_item_from_mm_object (G_LIST_MODEL (self->devices), mm_object);
413
414 if (!device)
415 return;
416
417 index = wwan_model_get_item_index (G_LIST_MODEL (self->data_devices), device);
418 if (index != -1) {
419 g_list_store_remove (self->data_devices, index);
420 g_list_store_remove (self->data_devices_name_list, index);
421 }
422
423 index = wwan_model_get_item_index (G_LIST_MODEL (self->devices), device);
424 if (index == -1)
425 return;
426
427 g_list_store_remove (self->devices, index);
428 stack_name = g_strdup_printf ("sim-%d", index + 1);
429 device_page = gtk_stack_get_child_by_name (self->devices_stack, stack_name);
430 gtk_stack_remove (GTK_STACK (self->devices_stack), device_page);
431
432 n_items = g_list_model_get_n_items (G_LIST_MODEL (self->data_devices));
433 g_list_model_items_changed (G_LIST_MODEL (self->data_devices), 0, n_items, n_items);
434
435 for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self->devices_stack));
436 child;
437 child = gtk_widget_get_next_sibling (child))
438 cc_wwan_panel_update_page_title (CC_WWAN_DEVICE_PAGE (child), self);
439 }
440
441 static void
442 wwan_panel_add_data_device_to_list (CcWwanPanel *self,
443 CcWwanDevice *device)
444 {
445 g_autoptr(GtkStringObject) str = NULL;
446 g_autofree char *operator = NULL;
447 int index;
448
449 index = wwan_model_get_item_index (G_LIST_MODEL (self->data_devices), device);
450 if (index != -1)
451 return;
452
453 g_list_store_append (self->data_devices, device);
454
455 index = wwan_model_get_item_index (G_LIST_MODEL (self->devices), device);
456 operator = g_strdup_printf ("SIM %d", index + 1);
457 str = gtk_string_object_new (operator);
458 g_object_set_data_full (G_OBJECT (str), "device", g_object_ref (device), g_object_unref);
459 g_list_store_append (self->data_devices_name_list, str);
460 }
461
462 static void
463 cc_wwan_panel_update_data_connections (CcWwanPanel *self)
464 {
465 CcWwanData *device_data, *active_data = NULL;
466 guint n_items;
467 gint i;
468
469 /*
470 * We can’t predict the order in which the data of device is enabled.
471 * But we have to keep data store in the same order as device store.
472 * So let’s remove every data device and re-add.
473 */
474 g_list_store_remove_all (self->data_devices);
475 g_list_store_remove_all (self->data_devices_name_list);
476 n_items = g_list_model_get_n_items (G_LIST_MODEL (self->devices));
477
478 for (i = 0; i < n_items; i++)
479 {
480 g_autoptr(CcWwanDevice) device = NULL;
481
482 device = g_list_model_get_item (G_LIST_MODEL (self->devices), i);
483 device_data = cc_wwan_device_get_data (device);
484
485 if (!device_data)
486 continue;
487
488 if ((!active_data ||
489 cc_wwan_data_get_priority (device_data) > cc_wwan_data_get_priority (active_data)) &&
490 cc_wwan_data_get_enabled (device_data))
491 {
492 active_data = device_data;
493 self->data_device = device;
494 }
495
496 if (cc_wwan_data_get_enabled (device_data))
497 wwan_panel_add_data_device_to_list (self, device);
498 }
499
500 if (active_data)
501 cc_wwan_panel_update_data_selection (self);
502 }
503
504 static void
505 cc_wwan_panel_update_devices (CcWwanPanel *self)
506 {
507 GList *devices, *iter;
508
509 devices = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->mm_manager));
510
511 for (iter = devices; iter; iter = iter->next)
512 {
513 MMObject *mm_object = iter->data;
514 CcWwanDevice *device;
515
516 if(!wwan_panel_device_is_supported (iter->data))
517 continue;
518
519 device = cc_wwan_device_new (mm_object, G_OBJECT (self->nm_client));
520 cc_wwan_panel_add_device (self, device);
521 g_signal_connect_object (device, "notify::has-data",
522 G_CALLBACK (cc_wwan_panel_update_data_connections),
523 self, G_CONNECT_SWAPPED);
524
525 if (cc_wwan_device_get_data (device))
526 wwan_panel_add_data_device_to_list (self, device);
527 }
528
529 cc_wwan_panel_update_data_connections (self);
530 handle_argv (self);
531 }
532
533 static void
534 wwan_panel_device_added_cb (CcWwanPanel *self,
535 GDBusObject *object)
536 {
537 CcWwanDevice *device;
538
539 if(!wwan_panel_device_is_supported (object))
540 return;
541
542 device = cc_wwan_device_new (MM_OBJECT (object), G_OBJECT (self->nm_client));
543 cc_wwan_panel_add_device (self, device);
544 g_signal_connect_object (device, "notify::has-data",
545 G_CALLBACK (cc_wwan_panel_update_data_connections),
546 self, G_CONNECT_SWAPPED);
547 cc_wwan_panel_update_view (self);
548 handle_argv (self);
549 }
550
551 static void
552 wwan_panel_device_removed_cb (CcWwanPanel *self,
553 GDBusObject *object)
554 {
555 if (!wwan_panel_device_is_supported (object))
556 return;
557
558 cc_wwan_panel_remove_mm_object (self, MM_OBJECT (object));
559
560 gtk_revealer_set_reveal_child (self->multi_device_revealer,
561 g_list_model_get_n_items (G_LIST_MODEL (self->devices)) > 1);
562 }
563
564 static GPtrArray *
565 variant_av_to_string_array (GVariant *array)
566 {
567 GVariant *v;
568 GPtrArray *strv;
569 GVariantIter iter;
570 gsize count;
571
572 count = g_variant_iter_init (&iter, array);
573 strv = g_ptr_array_sized_new (count + 1);
574
575 while (g_variant_iter_next (&iter, "v", &v))
576 {
577 g_ptr_array_add (strv, (gpointer)g_variant_get_string (v, NULL));
578 g_variant_unref (v);
579 }
580 g_ptr_array_add (strv, NULL); /* NULL-terminate the strv data array */
581
582 return strv;
583 }
584
585 static void
586 cc_wwan_panel_set_property (GObject *object,
587 guint property_id,
588 const GValue *value,
589 GParamSpec *pspec)
590 {
591 CcWwanPanel *self = CC_WWAN_PANEL (object);
592
593 switch (property_id)
594 {
595 case PROP_PARAMETERS:
596 {
597 GVariant *parameters;
598
599 reset_command_line_args (self);
600
601 parameters = g_value_get_variant (value);
602 if (parameters)
603 {
604 g_autoptr(GPtrArray) array = NULL;
605 const gchar **args;
606
607 array = variant_av_to_string_array (parameters);
608 args = (const gchar **) array->pdata;
609
610 g_debug ("Invoked with operation %s", args[0]);
611
612 if (args[0])
613 self->arg_operation = cmdline_operation_from_string (args[0]);
614 if (args[0] && args[1])
615 self->arg_device = g_strdup (args[1]);
616
617 if (!verify_argv (self, (const char **) args))
618 {
619 reset_command_line_args (self);
620 return;
621 }
622 g_debug ("Calling handle_argv() after setting property");
623 handle_argv (self);
624 }
625 break;
626 }
627 default:
628 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
629 }
630 }
631
632 static void
633 cc_wwan_panel_dispose (GObject *object)
634 {
635 CcWwanPanel *self = (CcWwanPanel *)object;
636
637 g_cancellable_cancel (self->cancellable);
638
639 g_clear_object (&self->devices);
640 g_clear_object (&self->data_devices);
641 g_clear_object (&self->data_devices_name_list);
642 g_clear_object (&self->mm_manager);
643 g_clear_object (&self->nm_client);
644 g_clear_object (&self->cancellable);
645 g_clear_object (&self->rfkill_proxy);
646 g_clear_pointer (&self->arg_device, g_free);
647
648 G_OBJECT_CLASS (cc_wwan_panel_parent_class)->dispose (object);
649 }
650
651 static void
652 cc_wwan_panel_class_init (CcWwanPanelClass *klass)
653 {
654 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
655 GObjectClass *object_class = G_OBJECT_CLASS (klass);
656
657 object_class->set_property = cc_wwan_panel_set_property;
658 object_class->dispose = cc_wwan_panel_dispose;
659
660 g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters");
661
662 gtk_widget_class_set_template_from_resource (widget_class,
663 "/org/gnome/control-center/wwan/cc-wwan-panel.ui");
664
665 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, toast_overlay);
666 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, data_list_row);
667 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, data_sim_select_listbox);
668 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, devices_stack);
669 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, devices_switcher);
670 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, enable_switch);
671 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, main_stack);
672 gtk_widget_class_bind_template_child (widget_class, CcWwanPanel, multi_device_revealer);
673
674 gtk_widget_class_bind_template_callback (widget_class, wwan_data_list_selected_sim_changed_cb);
675 gtk_widget_class_bind_template_callback (widget_class, wwan_on_airplane_off_clicked_cb);
676 gtk_widget_class_bind_template_callback (widget_class, cc_wwan_data_item_activate_cb);
677 }
678
679 static void
680 cc_wwan_panel_init (CcWwanPanel *self)
681 {
682 g_autoptr(GError) error = NULL;
683
684 g_resources_register (cc_wwan_get_resource ());
685
686 gtk_widget_init_template (GTK_WIDGET (self));
687
688 self->cancellable = g_cancellable_new ();
689 self->devices = g_list_store_new (CC_TYPE_WWAN_DEVICE);
690 self->data_devices = g_list_store_new (CC_TYPE_WWAN_DEVICE);
691 self->data_devices_name_list = g_list_store_new (GTK_TYPE_STRING_OBJECT);
692 adw_combo_row_set_model (ADW_COMBO_ROW (self->data_list_row),
693 G_LIST_MODEL (self->data_devices_name_list));
694
695 if (cc_object_storage_has_object (CC_OBJECT_NMCLIENT))
696 {
697 self->nm_client = cc_object_storage_get_object (CC_OBJECT_NMCLIENT);
698 g_signal_connect_object (self->nm_client,
699 "notify::wwan-enabled",
700 G_CALLBACK (cc_wwan_panel_update_view),
701 self, G_CONNECT_SWAPPED);
702
703 }
704 else
705 {
706 g_warn_if_reached ();
707 }
708
709 if (self->nm_client)
710 {
711 g_object_bind_property (self->nm_client, "wwan-enabled",
712 self->enable_switch, "active",
713 G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
714 }
715
716 if (cc_object_storage_has_object ("CcObjectStorage::mm-manager"))
717 {
718 self->mm_manager = cc_object_storage_get_object ("CcObjectStorage::mm-manager");
719
720 g_signal_connect_object (self->mm_manager, "object-added",
721 G_CALLBACK (wwan_panel_device_added_cb),
722 self, G_CONNECT_SWAPPED);
723 g_signal_connect_object (self->mm_manager, "object-removed",
724 G_CALLBACK (wwan_panel_device_removed_cb),
725 self, G_CONNECT_SWAPPED);
726
727 cc_wwan_panel_update_devices (self);
728 }
729 else
730 {
731 g_warn_if_reached ();
732 }
733
734 /* Acquire Airplane Mode proxy */
735 self->rfkill_proxy = cc_object_storage_create_dbus_proxy_sync (G_BUS_TYPE_SESSION,
736 G_DBUS_PROXY_FLAGS_NONE,
737 "org.gnome.SettingsDaemon.Rfkill",
738 "/org/gnome/SettingsDaemon/Rfkill",
739 "org.gnome.SettingsDaemon.Rfkill",
740 self->cancellable,
741 &error);
742
743 if (error)
744 {
745 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
746 g_printerr ("Error creating rfkill proxy: %s\n", error->message);
747 }
748 else
749 {
750 g_signal_connect_object (self->rfkill_proxy,
751 "g-properties-changed",
752 G_CALLBACK (cc_wwan_panel_update_view),
753 self, G_CONNECT_SWAPPED);
754
755 cc_wwan_panel_update_view (self);
756 }
757 }
758
759 static void
760 wwan_update_panel_visibility (MMManager *mm_manager)
761 {
762 CcApplication *application;
763 GList *devices;
764 gboolean has_wwan;
765
766 g_assert (MM_IS_MANAGER (mm_manager));
767
768 CC_TRACE_MSG ("Updating WWAN panel visibility");
769
770 has_wwan = FALSE;
771 devices = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (mm_manager));
772
773 for (GList *item = devices; item != NULL; item = item->next)
774 {
775 if(wwan_panel_device_is_supported (item->data))
776 {
777 has_wwan = TRUE;
778 break;
779 }
780 }
781
782 /* Set the new visibility */
783 application = CC_APPLICATION (g_application_get_default ());
784 cc_shell_model_set_panel_visibility (cc_application_get_model (application),
785 "wwan",
786 has_wwan ? CC_PANEL_VISIBLE : CC_PANEL_VISIBLE_IN_SEARCH);
787
788 g_debug ("WWAN panel visible: %s", has_wwan ? "yes" : "no");
789
790 g_list_free_full (devices, (GDestroyNotify)g_object_unref);
791 }
792
793 void
794 cc_wwan_panel_static_init_func (void)
795 {
796 g_autoptr(GDBusConnection) system_bus = NULL;
797 g_autoptr(MMManager) mm_manager = NULL;
798 g_autoptr(GError) error = NULL;
799
800 /*
801 * There could be other modems that are only handled by rfkill,
802 * and not available via ModemManager. But as this panel
803 * makes use of ModemManager APIs, we only care devices
804 * supported by ModemManager.
805 */
806 system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
807 if (system_bus == NULL)
808 g_warning ("Error connecting to system D-Bus: %s", error->message);
809 else
810 mm_manager = mm_manager_new_sync (system_bus,
811 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
812 NULL, &error);
813
814 if (mm_manager == NULL)
815 {
816 CcApplication *application;
817
818 g_warning ("Error connecting to ModemManager: %s", error->message);
819
820 application = CC_APPLICATION (g_application_get_default ());
821 cc_shell_model_set_panel_visibility (cc_application_get_model (application),
822 "wwan", FALSE);
823 return;
824 }
825 else
826 {
827 cc_object_storage_add_object ("CcObjectStorage::mm-manager", mm_manager);
828 }
829
830 g_debug ("Monitoring ModemManager for WWAN devices");
831
832 g_signal_connect (mm_manager, "object-added", G_CALLBACK (wwan_update_panel_visibility), NULL);
833 g_signal_connect (mm_manager, "object-removed", G_CALLBACK (wwan_update_panel_visibility), NULL);
834
835 wwan_update_panel_visibility (mm_manager);
836 }
837