GCC Code Coverage Report


Directory: ./
File: panels/network/cc-wifi-panel.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 365 0.0%
Functions: 0 35 0.0%
Branches: 0 219 0.0%

Line Branch Exec Source
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2017 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "cc-network-resources.h"
21 #include "cc-wifi-panel.h"
22 #include "cc-qr-code.h"
23 #include "net-device-wifi.h"
24 #include "network-dialogs.h"
25 #include "panel-common.h"
26
27 #include "shell/cc-application.h"
28 #include "shell/cc-log.h"
29 #include "shell/cc-object-storage.h"
30
31 #include <glib/gi18n.h>
32 #include <NetworkManager.h>
33
34 #define QR_IMAGE_SIZE 180
35
36 typedef enum
37 {
38 OPERATION_NULL,
39 OPERATION_SHOW_DEVICE,
40 OPERATION_CREATE_WIFI,
41 OPERATION_CONNECT_HIDDEN,
42 OPERATION_CONNECT_8021X
43 } CmdlineOperation;
44
45 struct _CcWifiPanel
46 {
47 CcPanel parent;
48
49 /* RFKill (Airplane Mode) */
50 GDBusProxy *rfkill_proxy;
51 AdwSwitchRow *rfkill_row;
52 GtkWidget *rfkill_widget;
53
54 /* Main widgets */
55 GtkStack *center_stack;
56 GtkStack *device_stack;
57 GtkBox *hotspot_box;
58 GtkLabel *list_label;
59 GtkStack *main_stack;
60 GtkWidget *spinner;
61 GtkStack *stack;
62 GtkPicture *wifi_qr_image;
63 CcQrCode *qr_code;
64
65 NMClient *client;
66
67 GPtrArray *devices;
68
69 GBinding *spinner_binding;
70
71 /* Command-line arguments */
72 CmdlineOperation arg_operation;
73 gchar *arg_device;
74 gchar *arg_access_point;
75 };
76
77 static void rfkill_switch_notify_activate_cb (CcWifiPanel *self);
78
79 static void update_devices_names (CcWifiPanel *self);
80
81 G_DEFINE_TYPE (CcWifiPanel, cc_wifi_panel, CC_TYPE_PANEL)
82
83 enum
84 {
85 PROP_0,
86 PROP_PARAMETERS,
87 N_PROPS
88 };
89
90 /* Static init function */
91
92 static void
93 update_panel_visibility (NMClient *client)
94 {
95 const GPtrArray *devices;
96 CcApplication *application;
97 gboolean visible;
98 guint i;
99
100 CC_TRACE_MSG ("Updating Wi-Fi panel visibility");
101
102 devices = nm_client_get_devices (client);
103 visible = FALSE;
104
105 for (i = 0; devices && i < devices->len; i++)
106 {
107 NMDevice *device = g_ptr_array_index (devices, i);
108
109 visible |= NM_IS_DEVICE_WIFI (device);
110
111 if (visible)
112 break;
113 }
114
115 /* Set the new visibility */
116 application = CC_APPLICATION (g_application_get_default ());
117 cc_shell_model_set_panel_visibility (cc_application_get_model (application),
118 "wifi",
119 visible ? CC_PANEL_VISIBLE : CC_PANEL_VISIBLE_IN_SEARCH);
120
121 g_debug ("Wi-Fi panel visible: %s", visible ? "yes" : "no");
122 }
123
124 void
125 cc_wifi_panel_static_init_func (void)
126 {
127 g_autoptr(NMClient) client = NULL;
128
129 g_debug ("Monitoring NetworkManager for Wi-Fi devices");
130
131 /* Create and store a NMClient instance if it doesn't exist yet */
132 if (!cc_object_storage_has_object (CC_OBJECT_NMCLIENT))
133 {
134 g_autoptr(NMClient) new_client = nm_client_new (NULL, NULL);
135 cc_object_storage_add_object (CC_OBJECT_NMCLIENT, new_client);
136 }
137
138 client = cc_object_storage_get_object (CC_OBJECT_NMCLIENT);
139
140 /* Update the panel visibility and monitor for changes */
141
142 g_signal_connect (client, "device-added", G_CALLBACK (update_panel_visibility), NULL);
143 g_signal_connect (client, "device-removed", G_CALLBACK (update_panel_visibility), NULL);
144
145 update_panel_visibility (client);
146 }
147
148 /* Auxiliary methods */
149
150 static NMConnection *
151 wifi_device_get_hotspot (CcWifiPanel *self,
152 NMDevice *device)
153 {
154 NMSettingIPConfig *ip4_setting;
155 NMConnection *c;
156
157 g_assert (CC_IS_WIFI_PANEL (self));
158 g_assert (NM_IS_DEVICE (device));
159
160 if (nm_device_get_active_connection (device) == NULL)
161 return NULL;
162
163 c = net_device_get_find_connection (self->client, device);
164 if (c == NULL)
165 return NULL;
166
167 ip4_setting = nm_connection_get_setting_ip4_config (c);
168 if (g_strcmp0 (nm_setting_ip_config_get_method (ip4_setting),
169 NM_SETTING_IP4_CONFIG_METHOD_SHARED) != 0)
170 return NULL;
171
172 return c;
173 }
174
175 static void
176 wifi_panel_update_qr_image_cb (CcWifiPanel *self)
177 {
178 NetDeviceWifi *child;
179 NMConnection *hotspot;
180 NMDevice *device;
181
182 g_assert (CC_IS_WIFI_PANEL (self));
183
184 child = NET_DEVICE_WIFI (gtk_stack_get_visible_child (self->stack));
185 device = net_device_wifi_get_device (child);
186 hotspot = wifi_device_get_hotspot (self, device);
187
188 if (hotspot)
189 {
190 g_autofree gchar *str = NULL;
191 g_autoptr (GVariant) secrets = NULL;
192 g_autoptr (GError) error = NULL;
193
194 if (!self->qr_code)
195 self->qr_code = cc_qr_code_new ();
196
197 secrets = nm_remote_connection_get_secrets (NM_REMOTE_CONNECTION (hotspot),
198 NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
199 NULL, &error);
200 if (!error) {
201 nm_connection_update_secrets (hotspot,
202 NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
203 secrets, &error);
204
205 str = get_qr_string_for_connection (hotspot);
206 if (cc_qr_code_set_text (self->qr_code, str))
207 {
208 GdkPaintable *paintable;
209 gint scale;
210
211 scale = gtk_widget_get_scale_factor (GTK_WIDGET (self->wifi_qr_image));
212 paintable = cc_qr_code_get_paintable (self->qr_code, QR_IMAGE_SIZE * scale);
213 gtk_picture_set_paintable (self->wifi_qr_image, paintable);
214 }
215 }
216 else
217 {
218 g_warning ("Error: %s", error->message);
219 }
220 }
221
222 gtk_widget_set_visible (GTK_WIDGET (self->hotspot_box), hotspot != NULL);
223 gtk_widget_set_opacity (GTK_WIDGET (self->list_label), hotspot == NULL);
224 gtk_widget_set_opacity (GTK_WIDGET (self->spinner), hotspot == NULL);
225 }
226
227 static void
228 add_wifi_device (CcWifiPanel *self,
229 NMDevice *device)
230 {
231 GtkWidget *header_widget;
232 NetDeviceWifi *net_device;
233
234 /* Create the NetDevice */
235 net_device = net_device_wifi_new (CC_PANEL (self),
236 self->client,
237 device);
238
239 /* And add to the header widgets */
240 header_widget = net_device_wifi_get_header_widget (net_device);
241
242 gtk_stack_add_named (self->device_stack, header_widget, nm_device_get_udi (device));
243
244 /* Setup custom title properties */
245 g_ptr_array_add (self->devices, net_device);
246
247 update_devices_names (self);
248
249 /* Needs to be added after the device is added to the self->devices array */
250 gtk_stack_add_titled (self->stack, GTK_WIDGET (net_device),
251 nm_device_get_udi (device),
252 nm_device_get_description (device));
253 g_signal_connect_object (device, "state-changed",
254 G_CALLBACK (wifi_panel_update_qr_image_cb),
255 self,
256 G_CONNECT_SWAPPED);
257 }
258
259 static void
260 remove_wifi_device (CcWifiPanel *self,
261 NMDevice *device)
262 {
263 GtkWidget *child;
264 const gchar *id;
265 guint i;
266
267 id = nm_device_get_udi (device);
268
269 /* Remove from the devices list */
270 for (i = 0; i < self->devices->len; i++)
271 {
272 NetDeviceWifi *net_device = g_ptr_array_index (self->devices, i);
273
274 if (net_device_wifi_get_device (net_device) == device)
275 {
276 g_ptr_array_remove (self->devices, net_device);
277 break;
278 }
279 }
280
281 /* Disconnect the signal to prevent assertion crash */
282 g_signal_handlers_disconnect_by_func (device,
283 G_CALLBACK (wifi_panel_update_qr_image_cb),
284 self);
285
286 /* Destroy all stack pages related to this device */
287 child = gtk_stack_get_child_by_name (self->stack, id);
288 gtk_stack_remove (self->stack, child);
289
290 child = gtk_stack_get_child_by_name (self->device_stack, id);
291 gtk_stack_remove (self->device_stack, child);
292
293 /* Update the title widget */
294 update_devices_names (self);
295 }
296
297 static void
298 check_main_stack_page (CcWifiPanel *self)
299 {
300 const gchar *nm_version;
301 gboolean airplane_mode_active;
302 gboolean wireless_hw_enabled;
303 gboolean wireless_enabled;
304
305 nm_version = nm_client_get_version (self->client);
306 wireless_hw_enabled = nm_client_wireless_hardware_get_enabled (self->client);
307 wireless_enabled = nm_client_wireless_get_enabled (self->client);
308 airplane_mode_active = adw_switch_row_get_active (self->rfkill_row);
309
310 if (!nm_version)
311 gtk_stack_set_visible_child_name (self->main_stack, "nm-not-running");
312 else if (!wireless_enabled && airplane_mode_active)
313 gtk_stack_set_visible_child_name (self->main_stack, "airplane-mode");
314 else if (!wireless_hw_enabled || self->devices->len == 0)
315 gtk_stack_set_visible_child_name (self->main_stack, "no-wifi-devices");
316 else if (!wireless_enabled)
317 gtk_stack_set_visible_child_name (self->main_stack, "wifi-off");
318 else
319 gtk_stack_set_visible_child_name (self->main_stack, "wifi-connections");
320 }
321
322 static void
323 load_wifi_devices (CcWifiPanel *self)
324 {
325 const GPtrArray *devices;
326 guint i;
327
328 devices = nm_client_get_devices (self->client);
329
330 /* Cold-plug existing devices */
331 if (devices)
332 {
333 for (i = 0; i < devices->len; i++)
334 {
335 NMDevice *device;
336
337 device = g_ptr_array_index (devices, i);
338 if (!NM_IS_DEVICE_WIFI (device) || !nm_device_get_managed (device))
339 continue;
340 add_wifi_device (self, device);
341 }
342 }
343
344 check_main_stack_page (self);
345 }
346
347 static inline gboolean
348 get_cached_rfkill_property (CcWifiPanel *self,
349 const gchar *property)
350 {
351 g_autoptr(GVariant) result = NULL;
352
353 result = g_dbus_proxy_get_cached_property (self->rfkill_proxy, property);
354 return result ? g_variant_get_boolean (result) : FALSE;
355 }
356
357 static void
358 sync_airplane_mode_switch (CcWifiPanel *self)
359 {
360 gboolean enabled, should_show, hw_enabled;
361
362 enabled = get_cached_rfkill_property (self, "HasAirplaneMode");
363 should_show = get_cached_rfkill_property (self, "ShouldShowAirplaneMode");
364
365 gtk_widget_set_visible (GTK_WIDGET (self->rfkill_widget), enabled && should_show);
366 if (!enabled || !should_show)
367 return;
368
369 enabled = get_cached_rfkill_property (self, "AirplaneMode");
370 hw_enabled = get_cached_rfkill_property (self, "HardwareAirplaneMode");
371
372 enabled |= hw_enabled;
373
374 if (enabled != adw_switch_row_get_active (self->rfkill_row))
375 {
376 g_signal_handlers_block_by_func (self->rfkill_row,
377 rfkill_switch_notify_activate_cb,
378 self);
379 g_object_set (self->rfkill_row, "active", enabled, NULL);
380 check_main_stack_page (self);
381 g_signal_handlers_unblock_by_func (self->rfkill_row,
382 rfkill_switch_notify_activate_cb,
383 self);
384 }
385
386 gtk_widget_set_sensitive (GTK_WIDGET (self->rfkill_row), !hw_enabled);
387
388 check_main_stack_page (self);
389 }
390
391 static void
392 update_devices_names (CcWifiPanel *self)
393 {
394 guint number_of_devices = self->devices->len;
395
396 if (number_of_devices == 1)
397 {
398 GtkWidget *title_widget;
399 NetDeviceWifi *net_device;
400
401 net_device = g_ptr_array_index (self->devices, 0);
402 title_widget = net_device_wifi_get_title_widget (net_device);
403
404 gtk_stack_add_named (self->center_stack, title_widget, "single");
405 gtk_stack_set_visible_child_name (self->center_stack, "single");
406
407 net_device_wifi_set_title (net_device, _("Wi-Fi"));
408 }
409 else
410 {
411 GtkWidget *single_page_widget;
412 guint i;
413
414 for (i = 0; i < number_of_devices; i++)
415 {
416 NetDeviceWifi *net_device;
417 NMDevice *device;
418
419 net_device = g_ptr_array_index (self->devices, i);
420 device = net_device_wifi_get_device (net_device);
421
422 net_device_wifi_set_title (net_device, nm_device_get_description (device));
423 }
424
425 /* Remove the widget at the "single" page */
426 single_page_widget = gtk_stack_get_child_by_name (self->center_stack, "single");
427
428 if (single_page_widget)
429 {
430 g_object_ref (single_page_widget);
431 gtk_stack_remove (self->center_stack, single_page_widget);
432 g_object_unref (single_page_widget);
433 }
434
435 /* Show the stack-switcher page */
436 gtk_stack_set_visible_child_name (self->center_stack, "many");
437 }
438 }
439
440 /* Command-line arguments */
441
442 static void
443 reset_command_line_args (CcWifiPanel *self)
444 {
445 self->arg_operation = OPERATION_NULL;
446 g_clear_pointer (&self->arg_device, g_free);
447 g_clear_pointer (&self->arg_access_point, g_free);
448 }
449
450 static gboolean
451 handle_argv_for_device (CcWifiPanel *self, NetDeviceWifi *net_device)
452 {
453 GtkWidget *toplevel;
454 NMDevice *device;
455 gboolean ret;
456
457 toplevel = cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)));
458 device = net_device_wifi_get_device (net_device);
459 ret = FALSE;
460
461 if (self->arg_operation == OPERATION_CREATE_WIFI)
462 {
463 cc_network_panel_create_wifi_network (toplevel, self->client);
464 ret = TRUE;
465 }
466 else if (self->arg_operation == OPERATION_CONNECT_HIDDEN)
467 {
468 cc_network_panel_connect_to_hidden_network (toplevel, self->client);
469 ret = TRUE;
470 }
471 else if (g_str_equal (nm_object_get_path (NM_OBJECT (device)), self->arg_device))
472 {
473 if (self->arg_operation == OPERATION_CONNECT_8021X)
474 {
475 cc_network_panel_connect_to_8021x_network (toplevel,
476 self->client,
477 device,
478 self->arg_access_point);
479 ret = TRUE;
480 }
481 else if (self->arg_operation == OPERATION_SHOW_DEVICE)
482 {
483 gtk_stack_set_visible_child_name (self->stack, nm_device_get_udi (device));
484 ret = TRUE;
485 }
486 }
487
488 if (ret)
489 reset_command_line_args (self);
490
491 return ret;
492 }
493
494 static void
495 handle_argv (CcWifiPanel *self)
496 {
497 guint i;
498
499 if (self->arg_operation == OPERATION_NULL)
500 return;
501
502 for (i = 0; i < self->devices->len; i++)
503 {
504 if (handle_argv_for_device (self, g_ptr_array_index (self->devices, i)))
505 break;
506 }
507 }
508
509 static GPtrArray *
510 variant_av_to_string_array (GVariant *array)
511 {
512 GVariantIter iter;
513 GVariant *v;
514 GPtrArray *strv;
515 gsize count;
516
517 count = g_variant_iter_init (&iter, array);
518 strv = g_ptr_array_sized_new (count + 1);
519
520 while (g_variant_iter_next (&iter, "v", &v))
521 {
522 g_ptr_array_add (strv, (gpointer) g_variant_get_string (v, NULL));
523 g_variant_unref (v);
524 }
525
526 g_ptr_array_add (strv, NULL); /* NULL-terminate the strv data array */
527 return strv;
528 }
529
530 static gboolean
531 verify_argv (CcWifiPanel *self,
532 const char **args)
533 {
534 switch (self->arg_operation)
535 {
536 case OPERATION_CONNECT_8021X:
537 case OPERATION_SHOW_DEVICE:
538 if (!self->arg_device)
539 {
540 g_warning ("Operation %s requires an object path", args[0]);
541 return FALSE;
542 }
543 default:
544 return TRUE;
545 }
546 }
547
548 /* Callbacks */
549
550 static void
551 device_state_changed_cb (CcWifiPanel *self, GParamSpec *pspec, NMDevice *device)
552 {
553 const gchar *id;
554
555 id = nm_device_get_udi (device);
556 /* Don't add a device that has already been added */
557 if (!NM_IS_DEVICE_WIFI (device) || !id)
558 return;
559
560 if (nm_device_get_managed (device))
561 {
562 if (gtk_stack_get_child_by_name (self->stack, id))
563 return;
564 add_wifi_device (self, device);
565 check_main_stack_page (self);
566 }
567 else
568 {
569 if (!gtk_stack_get_child_by_name (self->stack, id))
570 return;
571 remove_wifi_device (self, device);
572 check_main_stack_page (self);
573 }
574 }
575
576 static void
577 device_added_cb (CcWifiPanel *self, NMDevice *device)
578 {
579 if (!NM_IS_DEVICE_WIFI (device))
580 return;
581
582 if (nm_device_get_managed (device))
583 {
584 add_wifi_device (self, device);
585 check_main_stack_page (self);
586 }
587
588 g_signal_connect_object (device,
589 "notify::state",
590 G_CALLBACK (device_state_changed_cb),
591 self,
592 G_CONNECT_SWAPPED);
593 }
594
595 static void
596 device_removed_cb (CcWifiPanel *self, NMDevice *device)
597 {
598 const gchar *id;
599
600 if (!NM_IS_DEVICE_WIFI (device))
601 return;
602
603 id = nm_device_get_udi (device);
604 /* Don't remove a device that has already been removed */
605 if (!gtk_stack_get_child_by_name (self->stack, id))
606 return;
607
608 remove_wifi_device (self, device);
609 check_main_stack_page (self);
610
611 g_signal_handlers_disconnect_by_func (device,
612 G_CALLBACK (device_state_changed_cb),
613 self);
614 }
615
616 static void
617 wireless_enabled_cb (CcWifiPanel *self)
618 {
619 check_main_stack_page (self);
620 }
621
622 static void
623 on_rfkill_proxy_properties_changed_cb (CcWifiPanel *self)
624 {
625 g_debug ("Rfkill properties changed");
626
627 sync_airplane_mode_switch (self);
628 }
629
630 static void
631 rfkill_proxy_acquired_cb (GObject *source_object,
632 GAsyncResult *res,
633 gpointer user_data)
634 {
635 CcWifiPanel *self;
636 GDBusProxy *proxy;
637 g_autoptr(GError) error = NULL;
638
639 proxy = cc_object_storage_create_dbus_proxy_finish (res, &error);
640
641 if (error)
642 {
643 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
644 g_printerr ("Error creating rfkill proxy: %s\n", error->message);
645
646 return;
647 }
648
649 self = CC_WIFI_PANEL (user_data);
650
651 self->rfkill_proxy = proxy;
652
653 g_signal_connect_object (proxy,
654 "g-properties-changed",
655 G_CALLBACK (on_rfkill_proxy_properties_changed_cb),
656 self,
657 G_CONNECT_SWAPPED);
658
659 sync_airplane_mode_switch (self);
660 }
661
662 static void
663 rfkill_switch_notify_activate_cb (CcWifiPanel *self)
664 {
665 gboolean enable;
666
667 enable = adw_switch_row_get_active (self->rfkill_row);
668
669 g_dbus_proxy_call (self->rfkill_proxy,
670 "org.freedesktop.DBus.Properties.Set",
671 g_variant_new_parsed ("('org.gnome.SettingsDaemon.Rfkill',"
672 "'AirplaneMode', %v)",
673 g_variant_new_boolean (enable)),
674 G_DBUS_CALL_FLAGS_NONE,
675 -1,
676 cc_panel_get_cancellable (CC_PANEL (self)),
677 NULL,
678 NULL);
679 }
680
681 static void
682 on_stack_visible_child_changed_cb (CcWifiPanel *self)
683 {
684 const gchar *visible_device_id = NULL;
685 guint i;
686
687 wifi_panel_update_qr_image_cb (self);
688
689 /* Remove previous bindings */
690 g_clear_pointer (&self->spinner_binding, g_binding_unbind);
691
692 visible_device_id = gtk_stack_get_visible_child_name (self->stack);
693 for (i = 0; i < self->devices->len; i++)
694 {
695 NetDeviceWifi *net_device = g_ptr_array_index (self->devices, i);
696
697 if (g_strcmp0 (nm_device_get_udi (net_device_wifi_get_device (net_device)), visible_device_id) == 0)
698 {
699 self->spinner_binding = g_object_bind_property (net_device,
700 "scanning",
701 self->spinner,
702 "spinning",
703 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
704 break;
705 }
706 }
707 }
708
709 static void
710 on_stop_hotspot_dialog_response_cb (CcWifiPanel *self,
711 gchar *response,
712 AdwMessageDialog *dialog)
713 {
714 if (g_strcmp0 (response, "turn-off") == 0)
715 {
716 NetDeviceWifi *child;
717
718 child = NET_DEVICE_WIFI (gtk_stack_get_visible_child (self->stack));
719 net_device_wifi_turn_off_hotspot (child);
720 }
721
722 gtk_window_destroy (GTK_WINDOW (dialog));
723 }
724
725 static void
726 hotspot_stop_clicked_cb (CcWifiPanel *self)
727 {
728 GtkWidget *dialog;
729 GtkNative *native;
730
731 g_assert (CC_IS_WIFI_PANEL (self));
732
733 native = gtk_widget_get_native (GTK_WIDGET (self));
734
735 dialog = adw_message_dialog_new (GTK_WINDOW (native),
736 NULL,
737 _("Turning off will disconnect any devices that are using the hotspot."));
738
739 adw_message_dialog_format_heading (ADW_MESSAGE_DIALOG (dialog), _("Turn Off Hotspot?"));
740 adw_message_dialog_add_responses (ADW_MESSAGE_DIALOG (dialog),
741 "cancel", _("_Cancel"),
742 "turn-off", _("_Turn Off"),
743 NULL);
744 adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (dialog),
745 "turn-off",
746 ADW_RESPONSE_DESTRUCTIVE);
747 adw_message_dialog_set_default_response (ADW_MESSAGE_DIALOG (dialog), "cancel");
748 adw_message_dialog_set_close_response (ADW_MESSAGE_DIALOG (dialog), "cancel");
749
750 g_signal_connect_swapped (dialog, "response", G_CALLBACK (on_stop_hotspot_dialog_response_cb), self);
751 gtk_window_present (GTK_WINDOW (dialog));
752 }
753
754 /* Overrides */
755
756 static const gchar *
757 cc_wifi_panel_get_help_uri (CcPanel *panel)
758 {
759 return "help:gnome-help/net-wireless";
760 }
761
762 static void
763 cc_wifi_panel_finalize (GObject *object)
764 {
765 CcWifiPanel *self = (CcWifiPanel *)object;
766
767 g_clear_object (&self->client);
768 g_clear_object (&self->rfkill_proxy);
769
770 g_clear_pointer (&self->devices, g_ptr_array_unref);
771
772 reset_command_line_args (self);
773
774 G_OBJECT_CLASS (cc_wifi_panel_parent_class)->finalize (object);
775 }
776
777 static void
778 cc_wifi_panel_get_property (GObject *object,
779 guint prop_id,
780 GValue *value,
781 GParamSpec *pspec)
782 {
783 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
784 }
785
786 static void
787 cc_wifi_panel_set_property (GObject *object,
788 guint prop_id,
789 const GValue *value,
790 GParamSpec *pspec)
791 {
792 CcWifiPanel *self = CC_WIFI_PANEL (object);
793 GVariant *parameters;
794
795 switch (prop_id)
796 {
797 case PROP_PARAMETERS:
798 reset_command_line_args (self);
799
800 parameters = g_value_get_variant (value);
801
802 if (parameters)
803 {
804 g_autoptr(GPtrArray) array = NULL;
805 const gchar **args;
806
807 array = variant_av_to_string_array (parameters);
808 args = (const gchar **) array->pdata;
809
810 if (args[0])
811 {
812 if (g_str_equal (args[0], "create-wifi"))
813 self->arg_operation = OPERATION_CREATE_WIFI;
814 else if (g_str_equal (args[0], "connect-hidden-wifi"))
815 self->arg_operation = OPERATION_CONNECT_HIDDEN;
816 else if (g_str_equal (args[0], "connect-8021x-wifi"))
817 self->arg_operation = OPERATION_CONNECT_8021X;
818 else if (g_str_equal (args[0], "show-device"))
819 self->arg_operation = OPERATION_SHOW_DEVICE;
820 else
821 self->arg_operation = OPERATION_NULL;
822 }
823
824 if (args[0] && args[1])
825 self->arg_device = g_strdup (args[1]);
826 if (args[0] && args[1] && args[2])
827 self->arg_access_point = g_strdup (args[2]);
828
829 if (!verify_argv (self, (const char **) args))
830 {
831 reset_command_line_args (self);
832 return;
833 }
834
835 handle_argv (self);
836 }
837 break;
838
839 default:
840 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
841 }
842 }
843
844 static void
845 cc_wifi_panel_class_init (CcWifiPanelClass *klass)
846 {
847 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
848 GObjectClass *object_class = G_OBJECT_CLASS (klass);
849 CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
850
851 panel_class->get_help_uri = cc_wifi_panel_get_help_uri;
852
853 object_class->finalize = cc_wifi_panel_finalize;
854 object_class->get_property = cc_wifi_panel_get_property;
855 object_class->set_property = cc_wifi_panel_set_property;
856
857 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/network/cc-wifi-panel.ui");
858
859 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, center_stack);
860 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, device_stack);
861 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, hotspot_box);
862 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, list_label);
863 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, main_stack);
864 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, rfkill_row);
865 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, rfkill_widget);
866 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, spinner);
867 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, stack);
868 gtk_widget_class_bind_template_child (widget_class, CcWifiPanel, wifi_qr_image);
869
870 gtk_widget_class_bind_template_callback (widget_class, rfkill_switch_notify_activate_cb);
871 gtk_widget_class_bind_template_callback (widget_class, on_stack_visible_child_changed_cb);
872 gtk_widget_class_bind_template_callback (widget_class, hotspot_stop_clicked_cb);
873
874 g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters");
875 }
876
877 static void
878 cc_wifi_panel_init (CcWifiPanel *self)
879 {
880 g_autoptr(GtkCssProvider) provider = NULL;
881
882 g_resources_register (cc_network_get_resource ());
883
884 gtk_widget_init_template (GTK_WIDGET (self));
885
886 self->devices = g_ptr_array_new ();
887
888 /* Create and store a NMClient instance if it doesn't exist yet */
889 if (!cc_object_storage_has_object (CC_OBJECT_NMCLIENT))
890 {
891 g_autoptr(NMClient) client = nm_client_new (NULL, NULL);
892 cc_object_storage_add_object (CC_OBJECT_NMCLIENT, client);
893 }
894
895 /* Load NetworkManager */
896 self->client = cc_object_storage_get_object (CC_OBJECT_NMCLIENT);
897
898 g_signal_connect_object (self->client,
899 "device-added",
900 G_CALLBACK (device_added_cb),
901 self,
902 G_CONNECT_SWAPPED);
903
904 g_signal_connect_object (self->client,
905 "device-removed",
906 G_CALLBACK (device_removed_cb),
907 self,
908 G_CONNECT_SWAPPED);
909
910 g_signal_connect_object (self->client,
911 "notify::wireless-enabled",
912 G_CALLBACK (wireless_enabled_cb),
913 self,
914 G_CONNECT_SWAPPED);
915
916 /* Load Wi-Fi devices */
917 load_wifi_devices (self);
918
919 /* Acquire Airplane Mode proxy */
920 cc_object_storage_create_dbus_proxy (G_BUS_TYPE_SESSION,
921 G_DBUS_PROXY_FLAGS_NONE,
922 "org.gnome.SettingsDaemon.Rfkill",
923 "/org/gnome/SettingsDaemon/Rfkill",
924 "org.gnome.SettingsDaemon.Rfkill",
925 cc_panel_get_cancellable (CC_PANEL (self)),
926 rfkill_proxy_acquired_cb,
927 self);
928
929 /* Handle comment-line arguments after loading devices */
930 handle_argv (self);
931
932 /* use custom CSS */
933 provider = gtk_css_provider_new ();
934 gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/network/wifi-panel.css");
935 gtk_style_context_add_provider_for_display (gdk_display_get_default (),
936 GTK_STYLE_PROVIDER (provider),
937 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
938 }
939