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 |
|
|
|