1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2010-2012 Richard Hughes <richard@hughsie.com>
4  * Copyright (C) 2012 Thomas Bechtold <thomasbechtold@jpberlin.de>
5  * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include <config.h>
23 #include <glib/gi18n.h>
24 #include <stdlib.h>
25 
26 #include "cc-network-panel.h"
27 #include "cc-network-resources.h"
28 
29 #include <NetworkManager.h>
30 
31 #include "net-device.h"
32 #include "net-device-mobile.h"
33 #include "net-device-wifi.h"
34 #include "net-device-ethernet.h"
35 #include "net-object.h"
36 #include "net-proxy.h"
37 #include "net-vpn.h"
38 
39 #include "panel-common.h"
40 
41 #include "network-dialogs.h"
42 #include "connection-editor/net-connection-editor.h"
43 
44 #ifdef BUILD_MODEM
45 #include <libmm-glib.h>
46 #endif
47 
48 #ifdef HAVE_NMA_18
49 #include <nma-cert-chooser.h>
50 #endif
51 
52 CC_PANEL_REGISTER (CcNetworkPanel, cc_network_panel)
53 
54 #define NETWORK_PANEL_PRIVATE(o) \
55         (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_NETWORK_PANEL, CcNetworkPanelPrivate))
56 
57 typedef enum {
58         OPERATION_NULL,
59         OPERATION_SHOW_DEVICE,
60         OPERATION_CREATE_WIFI,
61         OPERATION_CONNECT_HIDDEN,
62         OPERATION_CONNECT_8021X,
63         OPERATION_CONNECT_MOBILE
64 } CmdlineOperation;
65 
66 struct _CcNetworkPanelPrivate
67 {
68         GCancellable     *cancellable;
69         GtkBuilder       *builder;
70         GtkWidget        *treeview;
71         NMClient         *client;
72 #ifdef BUILD_MODEM
73         MMManager        *modem_manager;
74 #else
75         void             *modem_manager;
76 #endif
77         gboolean          updating_device;
78 
79         /* wireless dialog stuff */
80         CmdlineOperation  arg_operation;
81         gchar            *arg_device;
82         gchar            *arg_access_point;
83         gboolean          operation_done;
84 };
85 
86 enum {
87         PANEL_DEVICES_COLUMN_ICON,
88         PANEL_DEVICES_COLUMN_OBJECT,
89         PANEL_DEVICES_COLUMN_LAST
90 };
91 
92 enum {
93         PROP_0,
94         PROP_PARAMETERS
95 };
96 
97 static NetObject *find_in_model_by_id (CcNetworkPanel *panel, const gchar *id, GtkTreeIter *iter_out);
98 static void handle_argv (CcNetworkPanel *panel);
99 
100 static void
cc_network_panel_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)101 cc_network_panel_get_property (GObject    *object,
102                                guint       property_id,
103                                GValue     *value,
104                                GParamSpec *pspec)
105 {
106         switch (property_id) {
107         default:
108                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
109         }
110 }
111 
112 static CmdlineOperation
cmdline_operation_from_string(const gchar * string)113 cmdline_operation_from_string (const gchar *string)
114 {
115         if (g_strcmp0 (string, "create-wifi") == 0)
116                 return OPERATION_CREATE_WIFI;
117         if (g_strcmp0 (string, "connect-hidden-wifi") == 0)
118                 return OPERATION_CONNECT_HIDDEN;
119         if (g_strcmp0 (string, "connect-8021x-wifi") == 0)
120                 return OPERATION_CONNECT_8021X;
121         if (g_strcmp0 (string, "connect-3g") == 0)
122                 return OPERATION_CONNECT_MOBILE;
123         if (g_strcmp0 (string, "show-device") == 0)
124                 return OPERATION_SHOW_DEVICE;
125 
126         g_warning ("Invalid additional argument %s", string);
127         return OPERATION_NULL;
128 }
129 
130 static void
reset_command_line_args(CcNetworkPanel * self)131 reset_command_line_args (CcNetworkPanel *self)
132 {
133 	self->priv->arg_operation = OPERATION_NULL;
134 	g_clear_pointer (&self->priv->arg_device, g_free);
135 	g_clear_pointer (&self->priv->arg_access_point, g_free);
136 }
137 
138 static gboolean
verify_argv(CcNetworkPanel * self,const char ** args)139 verify_argv (CcNetworkPanel *self,
140 	     const char    **args)
141 {
142 	switch (self->priv->arg_operation) {
143 	case OPERATION_CONNECT_MOBILE:
144 	case OPERATION_CONNECT_8021X:
145 	case OPERATION_SHOW_DEVICE:
146 		if (self->priv->arg_device == NULL) {
147 			g_warning ("Operation %s requires an object path", args[0]);
148 		        return FALSE;
149                 }
150 	default:
151 		return TRUE;
152 	}
153 }
154 
155 static GPtrArray *
variant_av_to_string_array(GVariant * array)156 variant_av_to_string_array (GVariant *array)
157 {
158         GVariantIter iter;
159         GVariant *v;
160         GPtrArray *strv;
161         gsize count;
162         count = g_variant_iter_init (&iter, array);
163         strv = g_ptr_array_sized_new (count + 1);
164         while (g_variant_iter_next (&iter, "v", &v)) {
165                 if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
166                         g_ptr_array_add (strv, (gpointer *)g_variant_get_string (v, NULL));
167                 g_variant_unref (v);
168         }
169         g_ptr_array_add (strv, NULL); /* NULL-terminate the strv data array */
170         return strv;
171 }
172 
173 static void
cc_network_panel_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)174 cc_network_panel_set_property (GObject      *object,
175                                guint         property_id,
176                                const GValue *value,
177                                GParamSpec   *pspec)
178 {
179         CcNetworkPanel *self = CC_NETWORK_PANEL (object);
180         CcNetworkPanelPrivate *priv = self->priv;
181 
182         switch (property_id) {
183         case PROP_PARAMETERS: {
184                 GVariant *parameters;
185 
186                 reset_command_line_args (self);
187 
188                 parameters = g_value_get_variant (value);
189                 if (parameters) {
190                         GPtrArray *array;
191                         const gchar **args;
192                         array = variant_av_to_string_array (parameters);
193                         args = (const gchar **) array->pdata;
194 
195                         g_debug ("Invoked with operation %s", args[0]);
196 
197                         if (args[0])
198                                 priv->arg_operation = cmdline_operation_from_string (args[0]);
199                         if (args[0] && args[1])
200                                 priv->arg_device = g_strdup (args[1]);
201                         if (args[0] && args[1] && args[2])
202                                 priv->arg_access_point = g_strdup (args[2]);
203 
204                         if (verify_argv (self, (const char **) args) == FALSE) {
205                                 reset_command_line_args (self);
206                                 g_ptr_array_unref (array);
207                                 return;
208                         }
209                         g_ptr_array_unref (array);
210                         g_debug ("Calling handle_argv() after setting property");
211                         handle_argv (self);
212                 }
213                 break;
214         }
215         default:
216                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
217         }
218 }
219 
220 static void
cc_network_panel_dispose(GObject * object)221 cc_network_panel_dispose (GObject *object)
222 {
223         CcNetworkPanelPrivate *priv = CC_NETWORK_PANEL (object)->priv;
224 
225         if (priv->cancellable != NULL)
226                 g_cancellable_cancel (priv->cancellable);
227 
228         g_clear_object (&priv->cancellable);
229         g_clear_object (&priv->builder);
230         g_clear_object (&priv->client);
231         g_clear_object (&priv->modem_manager);
232 
233         G_OBJECT_CLASS (cc_network_panel_parent_class)->dispose (object);
234 }
235 
236 static void
cc_network_panel_finalize(GObject * object)237 cc_network_panel_finalize (GObject *object)
238 {
239         CcNetworkPanel *panel = CC_NETWORK_PANEL (object);
240 
241         reset_command_line_args (panel);
242 
243         G_OBJECT_CLASS (cc_network_panel_parent_class)->finalize (object);
244 }
245 
246 static const char *
cc_network_panel_get_help_uri(CcPanel * panel)247 cc_network_panel_get_help_uri (CcPanel *panel)
248 {
249 	return "help:gnome-help/net";
250 }
251 
252 static void
cc_network_panel_class_init(CcNetworkPanelClass * klass)253 cc_network_panel_class_init (CcNetworkPanelClass *klass)
254 {
255         GObjectClass *object_class = G_OBJECT_CLASS (klass);
256         CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
257 
258         g_type_class_add_private (klass, sizeof (CcNetworkPanelPrivate));
259 
260         panel_class->get_help_uri = cc_network_panel_get_help_uri;
261 
262         object_class->get_property = cc_network_panel_get_property;
263         object_class->set_property = cc_network_panel_set_property;
264         object_class->dispose = cc_network_panel_dispose;
265         object_class->finalize = cc_network_panel_finalize;
266 
267         g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters");
268 }
269 
270 static NetObject *
get_selected_object(CcNetworkPanel * panel)271 get_selected_object (CcNetworkPanel *panel)
272 {
273         GtkTreeSelection *selection;
274         GtkTreeModel *model;
275         GtkTreeIter iter;
276         NetObject *object = NULL;
277 
278         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview));
279         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
280                 return NULL;
281         }
282 
283         gtk_tree_model_get (model, &iter,
284                             PANEL_DEVICES_COLUMN_OBJECT, &object,
285                             -1);
286 
287         return object;
288 }
289 
290 static void
select_first_device(CcNetworkPanel * panel)291 select_first_device (CcNetworkPanel *panel)
292 {
293         GtkTreePath *path;
294         GtkTreeSelection *selection;
295 
296         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview));
297 
298         /* select the first device */
299         path = gtk_tree_path_new_from_string ("0");
300         gtk_tree_selection_select_path (selection, path);
301         gtk_tree_path_free (path);
302 }
303 
304 static void
select_tree_iter(CcNetworkPanel * panel,GtkTreeIter * iter)305 select_tree_iter (CcNetworkPanel *panel, GtkTreeIter *iter)
306 {
307         GtkTreeSelection *selection;
308 
309         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview));
310 
311         gtk_tree_selection_select_iter (selection, iter);
312 }
313 
314 static void
object_removed_cb(NetObject * object,CcNetworkPanel * panel)315 object_removed_cb (NetObject *object, CcNetworkPanel *panel)
316 {
317         gboolean ret;
318         NetObject *object_tmp;
319         GtkTreeIter iter;
320         GtkTreeModel *model;
321         GtkTreeSelection *selection;
322 
323         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview));
324 
325         /* remove device from model */
326         model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder,
327                                                         "liststore_devices"));
328         ret = gtk_tree_model_get_iter_first (model, &iter);
329         if (!ret)
330                 return;
331 
332         /* get the other elements */
333         do {
334                 gtk_tree_model_get (model, &iter,
335                                     PANEL_DEVICES_COLUMN_OBJECT, &object_tmp,
336                                     -1);
337                 if (g_strcmp0 (net_object_get_id (object),
338                                net_object_get_id (object_tmp)) == 0) {
339                         g_object_unref (object_tmp);
340                         if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) {
341                                 if (gtk_tree_model_get_iter_first (model, &iter))
342                                         gtk_tree_selection_select_iter (selection, &iter);
343                         }
344                         break;
345                 }
346                 g_object_unref (object_tmp);
347         } while (gtk_tree_model_iter_next (model, &iter));
348 }
349 
350 GPtrArray *
cc_network_panel_get_devices(CcNetworkPanel * panel)351 cc_network_panel_get_devices (CcNetworkPanel *panel)
352 {
353         GPtrArray *devices;
354         GtkTreeModel *model;
355         GtkTreeIter iter;
356         NetObject *object;
357 
358         devices = g_ptr_array_new_with_free_func (g_object_unref);
359 
360         model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder,
361                                                         "liststore_devices"));
362         if (!gtk_tree_model_get_iter_first (model, &iter))
363                 return devices;
364 
365         do {
366                 gtk_tree_model_get (model, &iter,
367                                     PANEL_DEVICES_COLUMN_OBJECT, &object,
368                                     -1);
369                 if (NET_IS_DEVICE (object))
370                         g_ptr_array_add (devices, object);
371                 else
372                         g_object_unref (object);
373         } while (gtk_tree_model_iter_next (model, &iter));
374 
375         return devices;
376 }
377 
378 static gint
panel_net_object_get_sort_category(NetObject * net_object)379 panel_net_object_get_sort_category (NetObject *net_object)
380 {
381         if (NET_IS_DEVICE (net_object)) {
382                 return panel_device_get_sort_category (net_device_get_nm_device (NET_DEVICE (net_object)));
383         } else if (NET_IS_PROXY (net_object)) {
384                 return 9;
385         } else if (NET_IS_VPN (net_object)) {
386                 return 5;
387         }
388 
389         g_assert_not_reached ();
390 }
391 
392 static gint
panel_net_object_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,void * data)393 panel_net_object_sort_func (GtkTreeModel *model, GtkTreeIter *a,
394                             GtkTreeIter *b, void *data)
395 {
396         g_autoptr(NetObject) obj_a = NULL;
397         g_autoptr(NetObject) obj_b = NULL;
398         gint cat_a, cat_b;
399         const char *title_a, *title_b;
400 
401         gtk_tree_model_get (model, a,
402                             PANEL_DEVICES_COLUMN_OBJECT, &obj_a,
403                             -1);
404         gtk_tree_model_get (model, b,
405                             PANEL_DEVICES_COLUMN_OBJECT, &obj_b,
406                             -1);
407 
408         cat_a = panel_net_object_get_sort_category (obj_a);
409         cat_b = panel_net_object_get_sort_category (obj_b);
410 
411         if (cat_a != cat_b)
412                 return cat_a - cat_b;
413 
414         title_a = net_object_get_title (obj_a);
415         title_b = net_object_get_title (obj_b);
416 
417         if (title_a == title_b)
418                 return 0;
419         if (title_a == NULL)
420                 return -1;
421         if (title_b == NULL)
422                 return 1;
423 
424         return g_utf8_collate (title_a, title_b);
425 }
426 
427 static void
panel_net_object_notify_title_cb(NetObject * net_object,GParamSpec * pspec,CcNetworkPanel * panel)428 panel_net_object_notify_title_cb (NetObject *net_object, GParamSpec *pspec, CcNetworkPanel *panel)
429 {
430         GtkTreeIter iter;
431         GtkListStore *liststore;
432 
433         if (!find_in_model_by_id (panel, net_object_get_id (net_object), &iter))
434                 return;
435 
436         liststore = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder,
437                                                             "liststore_devices"));
438 
439         /* gtk_tree_model_row_changed would not cause the list store to resort.
440          * Instead set the object column to the current value.
441          * See https://bugzilla.gnome.org/show_bug.cgi?id=782737 */
442         gtk_list_store_set (liststore, &iter,
443                             PANEL_DEVICES_COLUMN_OBJECT, net_object,
444                            -1);
445 }
446 
447 static void
panel_refresh_device_titles(CcNetworkPanel * panel)448 panel_refresh_device_titles (CcNetworkPanel *panel)
449 {
450         GPtrArray *ndarray, *nmdarray;
451         NetDevice **devices;
452         NMDevice **nm_devices, *nm_device;
453         gchar **titles;
454         gint i, num_devices;
455 
456         ndarray = cc_network_panel_get_devices (panel);
457         if (!ndarray->len) {
458                 g_ptr_array_free (ndarray, TRUE);
459                 return;
460         }
461 
462         nmdarray = g_ptr_array_new ();
463         for (i = 0; i < ndarray->len; i++) {
464                 nm_device = net_device_get_nm_device (ndarray->pdata[i]);
465                 if (nm_device)
466                         g_ptr_array_add (nmdarray, nm_device);
467                 else
468                         g_ptr_array_remove_index (ndarray, i--);
469         }
470 
471         devices = (NetDevice **)ndarray->pdata;
472         nm_devices = (NMDevice **)nmdarray->pdata;
473         num_devices = ndarray->len;
474 
475         titles = nm_device_disambiguate_names (nm_devices, num_devices);
476         for (i = 0; i < num_devices; i++) {
477                 net_object_set_title (NET_OBJECT (devices[i]), titles[i]);
478                 g_free (titles[i]);
479         }
480         g_free (titles);
481         g_ptr_array_free (ndarray, TRUE);
482         g_ptr_array_free (nmdarray, TRUE);
483 }
484 
485 static gboolean
handle_argv_for_device(CcNetworkPanel * panel,NMDevice * device,GtkTreeIter * iter)486 handle_argv_for_device (CcNetworkPanel *panel,
487 			NMDevice       *device,
488 			GtkTreeIter    *iter)
489 {
490         CcNetworkPanelPrivate *priv = panel->priv;
491         NMDeviceType type;
492         //GtkWidget *toplevel = cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)));
493         GtkWidget *toplevel = GTK_WIDGET(panel);
494 
495         if (priv->arg_operation == OPERATION_NULL)
496                 return TRUE;
497 
498         type = nm_device_get_device_type (device);
499 
500         if (type == NM_DEVICE_TYPE_WIFI &&
501             (priv->arg_operation == OPERATION_CREATE_WIFI ||
502              priv->arg_operation == OPERATION_CONNECT_HIDDEN)) {
503                 g_debug ("Selecting wifi device");
504                 select_tree_iter (panel, iter);
505 
506                 if (priv->arg_operation == OPERATION_CREATE_WIFI)
507                         cc_network_panel_create_wifi_network (toplevel, priv->client);
508                 else
509                         cc_network_panel_connect_to_hidden_network (toplevel, priv->client);
510 
511                 reset_command_line_args (panel); /* done */
512                 return TRUE;
513         } else if (g_strcmp0 (nm_object_get_path (NM_OBJECT (device)), priv->arg_device) == 0) {
514                 if (priv->arg_operation == OPERATION_CONNECT_MOBILE) {
515                         cc_network_panel_connect_to_3g_network (toplevel, priv->client, device);
516 
517                         reset_command_line_args (panel); /* done */
518                         select_tree_iter (panel, iter);
519                         return TRUE;
520                 } else if (priv->arg_operation == OPERATION_CONNECT_8021X) {
521                         cc_network_panel_connect_to_8021x_network (toplevel, priv->client, device, priv->arg_access_point);
522                         reset_command_line_args (panel); /* done */
523                         select_tree_iter (panel, iter);
524                         return TRUE;
525                 }
526                 else if (priv->arg_operation == OPERATION_SHOW_DEVICE) {
527                         select_tree_iter (panel, iter);
528                         reset_command_line_args (panel); /* done */
529                         return TRUE;
530                 }
531         }
532 
533         return FALSE;
534 }
535 
536 static gboolean
handle_argv_for_connection(CcNetworkPanel * panel,NMConnection * connection,GtkTreeIter * iter)537 handle_argv_for_connection (CcNetworkPanel *panel,
538                             NMConnection   *connection,
539                             GtkTreeIter    *iter)
540 {
541         CcNetworkPanelPrivate *priv = panel->priv;
542 
543         if (priv->arg_operation == OPERATION_NULL)
544                 return TRUE;
545         if (priv->arg_operation != OPERATION_SHOW_DEVICE)
546                 return FALSE;
547 
548         if (g_strcmp0 (nm_connection_get_path (connection), priv->arg_device) == 0) {
549                 reset_command_line_args (panel);
550                 select_tree_iter (panel, iter);
551                 return TRUE;
552         }
553 
554         return FALSE;
555 }
556 
557 
558 static void
handle_argv(CcNetworkPanel * panel)559 handle_argv (CcNetworkPanel *panel)
560 {
561         GtkTreeModel *model;
562         GtkTreeIter iter;
563         gboolean ret;
564 
565         if (panel->priv->arg_operation == OPERATION_NULL)
566                 return;
567 
568         model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder,
569                                                         "liststore_devices"));
570         ret = gtk_tree_model_get_iter_first (model, &iter);
571         while (ret) {
572                 GObject *object_tmp;
573                 NMDevice *device;
574                 NMConnection *connection;
575                 gboolean done = FALSE;
576 
577                 gtk_tree_model_get (model, &iter,
578                                     PANEL_DEVICES_COLUMN_OBJECT, &object_tmp,
579                                     -1);
580                 if (NET_IS_DEVICE (object_tmp)) {
581                         g_object_get (object_tmp, "nm-device", &device, NULL);
582                         done = handle_argv_for_device (panel, device, &iter);
583                         g_object_unref (device);
584                 } else if (NET_IS_VPN (object_tmp)) {
585                         g_object_get (object_tmp, "connection", &connection, NULL);
586                         done = handle_argv_for_connection (panel, connection, &iter);
587                         g_object_unref (connection);
588                 }
589 
590                 g_object_unref (object_tmp);
591 
592                 if (done)
593                         return;
594 
595                 ret = gtk_tree_model_iter_next (model, &iter);
596         }
597 
598         g_debug ("Could not handle argv operation, no matching device yet?");
599 }
600 
601 static void
state_changed_cb(NMDevice * device,NMDeviceState new_state,NMDeviceState old_state,NMDeviceStateReason reason,CcNetworkPanel * panel)602 state_changed_cb (NMDevice *device,
603                   NMDeviceState new_state,
604                   NMDeviceState old_state,
605                   NMDeviceStateReason reason,
606                   CcNetworkPanel *panel)
607 {
608         GtkListStore *store;
609         GtkTreeIter iter;
610 
611         if (!find_in_model_by_id (panel, nm_device_get_udi (device), &iter)) {
612                 return;
613         }
614 
615         store = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder,
616                                                         "liststore_devices"));
617 
618         gtk_list_store_set (store, &iter,
619                             PANEL_DEVICES_COLUMN_ICON, panel_device_to_icon_name (device, TRUE),
620                            -1);
621 }
622 
623 static gboolean
panel_add_device(CcNetworkPanel * panel,NMDevice * device)624 panel_add_device (CcNetworkPanel *panel, NMDevice *device)
625 {
626         GtkListStore *liststore_devices;
627         GtkTreeIter iter;
628         NMDeviceType type;
629         NetDevice *net_device;
630         CcNetworkPanelPrivate *priv = panel->priv;
631         GtkNotebook *notebook;
632         GtkSizeGroup *size_group;
633         GType device_g_type;
634         const char *udi;
635 
636         if (!nm_device_get_managed (device))
637                 goto out;
638 
639         /* do we have an existing object with this id? */
640         udi = nm_device_get_udi (device);
641         if (find_in_model_by_id (panel, udi, NULL) != NULL)
642                 goto out;
643 
644         type = nm_device_get_device_type (device);
645 
646         g_debug ("device %s type %i path %s",
647                  udi, type, nm_object_get_path (NM_OBJECT (device)));
648 
649         /* map the NMDeviceType to the GType, or ignore */
650         switch (type) {
651         case NM_DEVICE_TYPE_ETHERNET:
652                 device_g_type = NET_TYPE_DEVICE_ETHERNET;
653                 break;
654         case NM_DEVICE_TYPE_MODEM:
655                 device_g_type = NET_TYPE_DEVICE_MOBILE;
656                 break;
657         case NM_DEVICE_TYPE_WIFI:
658                 device_g_type = NET_TYPE_DEVICE_WIFI;
659                 break;
660         /* not going to set up a cluster in GNOME */
661         case NM_DEVICE_TYPE_VETH:
662         /* enterprise features */
663         case NM_DEVICE_TYPE_BOND:
664         case NM_DEVICE_TYPE_TEAM:
665         /* Don't need the libvirtd bridge */
666         case NM_DEVICE_TYPE_BRIDGE:
667         /* Don't add VPN devices */
668         case NM_DEVICE_TYPE_TUN:
669                 goto out;
670         default:
671                 device_g_type = NET_TYPE_DEVICE_SIMPLE;
672                 break;
673         }
674 
675         /* create device */
676         net_device = g_object_new (device_g_type,
677                                    "panel", panel,
678                                    "removable", FALSE,
679                                    "cancellable", panel->priv->cancellable,
680                                    "client", panel->priv->client,
681                                    "nm-device", device,
682                                    "id", nm_device_get_udi (device),
683                                    NULL);
684 
685         if (type == NM_DEVICE_TYPE_MODEM &&
686             g_str_has_prefix (nm_device_get_udi (device), "/org/freedesktop/ModemManager1/Modem/")) {
687                 GDBusObject *modem_object;
688 
689                 if (priv->modem_manager == NULL) {
690                         g_warning ("Cannot grab information for modem at %s: No ModemManager support",
691                                    nm_device_get_udi (device));
692                         goto out;
693                 }
694 
695                 modem_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (priv->modem_manager),
696                                                                  nm_device_get_udi (device));
697                 if (modem_object == NULL) {
698                         g_warning ("Cannot grab information for modem at %s: Not found",
699                                    nm_device_get_udi (device));
700                         goto out;
701                 }
702 
703                 /* Set the modem object in the NetDeviceMobile */
704                 g_object_set (net_device,
705                               "mm-object", modem_object,
706                               NULL);
707                 g_object_unref (modem_object);
708         }
709 
710         /* add as a panel */
711         if (device_g_type != NET_TYPE_DEVICE) {
712                 notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->priv->builder,
713                                                                  "notebook_types"));
714                 size_group = GTK_SIZE_GROUP (gtk_builder_get_object (panel->priv->builder,
715                                                                      "sizegroup1"));
716                 net_object_add_to_notebook (NET_OBJECT (net_device),
717                                             notebook,
718                                             size_group);
719         }
720 
721         liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (priv->builder,
722                                             "liststore_devices"));
723         g_signal_connect_object (net_device, "removed",
724                                  G_CALLBACK (object_removed_cb), panel, 0);
725         gtk_list_store_append (liststore_devices, &iter);
726         gtk_list_store_set (liststore_devices,
727                             &iter,
728                             PANEL_DEVICES_COLUMN_ICON, panel_device_to_icon_name (device, TRUE),
729                             PANEL_DEVICES_COLUMN_OBJECT, net_device,
730                             -1);
731         g_signal_connect (net_device, "notify::title",
732                           G_CALLBACK (panel_net_object_notify_title_cb), panel);
733 
734         g_object_unref (net_device);
735         g_signal_connect (device, "state-changed",
736                           G_CALLBACK (state_changed_cb), panel);
737 
738 out:
739         return FALSE;
740 }
741 
742 static void
panel_remove_device(CcNetworkPanel * panel,NMDevice * device)743 panel_remove_device (CcNetworkPanel *panel, NMDevice *device)
744 {
745         gboolean ret;
746         NetObject *object_tmp;
747         GtkTreeIter iter;
748         GtkTreeModel *model;
749 
750         /* remove device from model */
751         model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder,
752                                                         "liststore_devices"));
753         ret = gtk_tree_model_get_iter_first (model, &iter);
754         if (!ret)
755                 return;
756 
757         /* get the other elements */
758         do {
759                 gtk_tree_model_get (model, &iter,
760                                     PANEL_DEVICES_COLUMN_OBJECT, &object_tmp,
761                                     -1);
762                 if (g_strcmp0 (net_object_get_id (object_tmp),
763                                nm_device_get_udi (device)) == 0) {
764                         gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
765                         g_object_unref (object_tmp);
766                         break;
767                 }
768                 g_object_unref (object_tmp);
769         } while (gtk_tree_model_iter_next (model, &iter));
770 }
771 
772 static void
get_object_title(GtkTreeViewColumn * column,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)773 get_object_title (GtkTreeViewColumn *column,
774                   GtkCellRenderer   *cell,
775                   GtkTreeModel      *model,
776                   GtkTreeIter       *iter,
777                   gpointer           data)
778 {
779         NetObject *object;
780 
781         gtk_tree_model_get (model, iter,
782                             PANEL_DEVICES_COLUMN_OBJECT, &object,
783                             -1);
784         if (!object)
785                 return;
786 
787         g_object_set (cell, "text", net_object_get_title (object), NULL);
788         g_object_unref (object);
789 }
790 
791 static void
panel_add_devices_columns(CcNetworkPanel * panel,GtkTreeView * treeview)792 panel_add_devices_columns (CcNetworkPanel *panel, GtkTreeView *treeview)
793 {
794         CcNetworkPanelPrivate *priv = panel->priv;
795         GtkCellRenderer *renderer;
796         GtkListStore *liststore_devices;
797         GtkTreeViewColumn *column;
798 
799         /* image */
800         renderer = gtk_cell_renderer_pixbuf_new ();
801         g_object_set (renderer,
802                       "width", 32,
803                       "xalign", 1.0,
804                       "stock-size", GTK_ICON_SIZE_MENU,
805                       "follow-state", TRUE,
806                       NULL);
807         gtk_cell_renderer_set_padding (renderer, 4, 10);
808 
809         column = gtk_tree_view_column_new_with_attributes ("icon", renderer,
810                                                            "icon-name", PANEL_DEVICES_COLUMN_ICON,
811                                                            NULL);
812         gtk_tree_view_append_column (treeview, column);
813 
814         /* column for text */
815         renderer = gtk_cell_renderer_text_new ();
816         g_object_set (renderer,
817                       "wrap-mode", PANGO_WRAP_WORD,
818                       "ellipsize", PANGO_ELLIPSIZE_END,
819                       NULL);
820         column = gtk_tree_view_column_new_with_attributes ("title", renderer, NULL);
821         gtk_tree_view_column_set_cell_data_func (GTK_TREE_VIEW_COLUMN (column),
822                                                  renderer,
823                                                  get_object_title,
824                                                  NULL, NULL);
825         gtk_tree_view_column_set_sort_column_id (column, PANEL_DEVICES_COLUMN_OBJECT);
826         liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (priv->builder,
827                                             "liststore_devices"));
828         gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (liststore_devices),
829                                          PANEL_DEVICES_COLUMN_OBJECT,
830                                          panel_net_object_sort_func, NULL, NULL);
831         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (liststore_devices),
832                                               PANEL_DEVICES_COLUMN_OBJECT,
833                                               GTK_SORT_ASCENDING);
834         gtk_tree_view_append_column (treeview, column);
835         gtk_tree_view_column_set_expand (column, TRUE);
836 }
837 
838 static void
nm_devices_treeview_clicked_cb(GtkTreeSelection * selection,CcNetworkPanel * panel)839 nm_devices_treeview_clicked_cb (GtkTreeSelection *selection, CcNetworkPanel *panel)
840 {
841         CcNetworkPanelPrivate *priv = panel->priv;
842         const gchar *id_tmp;
843         const gchar *needle;
844         GList *l;
845         GList *panels = NULL;
846         GtkNotebook *notebook;
847         GtkTreeIter iter;
848         GtkTreeModel *model;
849         GtkWidget *widget;
850         guint i = 0;
851         NetObject *object = NULL;
852 
853         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
854                 g_debug ("no row selected");
855                 goto out;
856         }
857 
858         /* find the widget in the notebook that matches the object ID */
859         object = get_selected_object (panel);
860         needle = net_object_get_id (object);
861         notebook = GTK_NOTEBOOK (gtk_builder_get_object (priv->builder,
862                                                          "notebook_types"));
863         panels = gtk_container_get_children (GTK_CONTAINER (notebook));
864         for (l = panels; l != NULL; l = l->next) {
865                 widget = GTK_WIDGET (l->data);
866                 id_tmp = g_object_get_data (G_OBJECT (widget), "NetObject::id");
867                 if (g_strcmp0 (needle, id_tmp) == 0) {
868                         gtk_notebook_set_current_page (notebook, i);
869 
870                         /* object is deletable? */
871                         widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
872                                                                      "remove_toolbutton"));
873                         gtk_widget_set_sensitive (widget,
874                                                   net_object_get_removable (object));
875                         break;
876                 }
877                 i++;
878         }
879         g_object_unref (object);
880 out:
881         g_list_free (panels);
882 }
883 
884 static void
panel_add_proxy_device(CcNetworkPanel * panel)885 panel_add_proxy_device (CcNetworkPanel *panel)
886 {
887         GtkListStore *liststore_devices;
888         GtkTreeIter iter;
889         NetProxy *proxy;
890         GtkNotebook *notebook;
891         GtkSizeGroup *size_group;
892 
893         /* add proxy to notebook */
894         proxy = net_proxy_new ();
895         notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->priv->builder,
896                                                          "notebook_types"));
897         size_group = GTK_SIZE_GROUP (gtk_builder_get_object (panel->priv->builder,
898                                                              "sizegroup1"));
899         net_object_add_to_notebook (NET_OBJECT (proxy),
900                                     notebook,
901                                     size_group);
902 
903         /* add proxy to device list */
904         liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder,
905                                             "liststore_devices"));
906         net_object_set_title (NET_OBJECT (proxy), _("Network proxy"));
907         gtk_list_store_append (liststore_devices, &iter);
908         gtk_list_store_set (liststore_devices,
909                             &iter,
910                             PANEL_DEVICES_COLUMN_ICON, "preferences-system-network-symbolic",
911                             PANEL_DEVICES_COLUMN_OBJECT, proxy,
912                             -1);
913 
914         /* NOTE: No connect to notify::title here as it is guaranteed to not
915          *       be changed by anyone.*/
916 
917         g_object_unref (proxy);
918 }
919 
920 static void
connection_state_changed(NMActiveConnection * c,GParamSpec * pspec,CcNetworkPanel * panel)921 connection_state_changed (NMActiveConnection *c, GParamSpec *pspec, CcNetworkPanel *panel)
922 {
923 }
924 
925 static void
active_connections_changed(NMClient * client,GParamSpec * pspec,gpointer user_data)926 active_connections_changed (NMClient *client, GParamSpec *pspec, gpointer user_data)
927 {
928         CcNetworkPanel *panel = user_data;
929         const GPtrArray *connections;
930         int i, j;
931 
932         g_debug ("Active connections changed:");
933         connections = nm_client_get_active_connections (client);
934         for (i = 0; connections && (i < connections->len); i++) {
935                 NMActiveConnection *connection;
936                 const GPtrArray *devices;
937 
938                 connection = g_ptr_array_index (connections, i);
939                 g_debug ("    %s", nm_object_get_path (NM_OBJECT (connection)));
940                 devices = nm_active_connection_get_devices (connection);
941                 for (j = 0; devices && j < devices->len; j++)
942                         g_debug ("           %s", nm_device_get_udi (g_ptr_array_index (devices, j)));
943                 if (NM_IS_VPN_CONNECTION (connection))
944                         g_debug ("           VPN base connection: %s", nm_active_connection_get_specific_object_path (connection));
945 
946                 if (g_object_get_data (G_OBJECT (connection), "has-state-changed-handler") == NULL) {
947                         g_signal_connect_object (connection, "notify::state",
948                                                  G_CALLBACK (connection_state_changed), panel, 0);
949                         g_object_set_data (G_OBJECT (connection), "has-state-changed-handler", GINT_TO_POINTER (TRUE));
950                 }
951         }
952 }
953 
954 static void
device_added_cb(NMClient * client,NMDevice * device,CcNetworkPanel * panel)955 device_added_cb (NMClient *client, NMDevice *device, CcNetworkPanel *panel)
956 {
957         g_debug ("New device added");
958         panel_add_device (panel, device);
959         panel_refresh_device_titles (panel);
960 }
961 
962 static void
device_removed_cb(NMClient * client,NMDevice * device,CcNetworkPanel * panel)963 device_removed_cb (NMClient *client, NMDevice *device, CcNetworkPanel *panel)
964 {
965         g_debug ("Device removed");
966         panel_remove_device (panel, device);
967         panel_refresh_device_titles (panel);
968 }
969 
970 static void
manager_running(NMClient * client,GParamSpec * pspec,gpointer user_data)971 manager_running (NMClient *client, GParamSpec *pspec, gpointer user_data)
972 {
973         const GPtrArray *devices;
974         int i;
975         NMDevice *device_tmp;
976         GtkListStore *liststore_devices;
977         gboolean selected = FALSE;
978         CcNetworkPanel *panel = CC_NETWORK_PANEL (user_data);
979 
980         /* clear all devices we added */
981         if (!nm_client_get_nm_running (client)) {
982                 g_debug ("NM disappeared");
983                 liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder,
984                                                     "liststore_devices"));
985                 gtk_list_store_clear (liststore_devices);
986                 panel_add_proxy_device (panel);
987                 goto out;
988         }
989 
990         g_debug ("coldplugging devices");
991         devices = nm_client_get_devices (client);
992         if (devices == NULL) {
993                 g_debug ("No devices to add");
994                 return;
995         }
996         for (i = 0; i < devices->len; i++) {
997                 device_tmp = g_ptr_array_index (devices, i);
998                 selected = panel_add_device (panel, device_tmp) || selected;
999         }
1000 out:
1001         if (!selected) {
1002                 /* select the first device */
1003                 select_first_device (panel);
1004         }
1005 
1006         panel_refresh_device_titles (panel);
1007 
1008         g_debug ("Calling handle_argv() after cold-plugging devices");
1009         handle_argv (panel);
1010 }
1011 
1012 static NetObject *
find_in_model_by_id(CcNetworkPanel * panel,const gchar * id,GtkTreeIter * iter_out)1013 find_in_model_by_id (CcNetworkPanel *panel, const gchar *id, GtkTreeIter *iter_out)
1014 {
1015         gboolean ret;
1016         NetObject *object_tmp;
1017         GtkTreeIter iter;
1018         GtkTreeModel *model;
1019         NetObject *object = NULL;
1020 
1021         /* find in model */
1022         model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder,
1023                                                         "liststore_devices"));
1024         ret = gtk_tree_model_get_iter_first (model, &iter);
1025         if (!ret)
1026                 goto out;
1027 
1028         /* get the other elements */
1029         ret = FALSE;
1030         do {
1031                 gtk_tree_model_get (model, &iter,
1032                                     PANEL_DEVICES_COLUMN_OBJECT, &object_tmp,
1033                                     -1);
1034                 if (object_tmp != NULL) {
1035                         g_debug ("got %s", net_object_get_id (object_tmp));
1036                         if (g_strcmp0 (net_object_get_id (object_tmp), id) == 0)
1037                                 object = object_tmp;
1038                         g_object_unref (object_tmp);
1039                 }
1040         } while (object == NULL && gtk_tree_model_iter_next (model, &iter));
1041 out:
1042         if (iter_out)
1043                 *iter_out = iter;
1044         return object;
1045 }
1046 
1047 static void
panel_add_vpn_device(CcNetworkPanel * panel,NMConnection * connection)1048 panel_add_vpn_device (CcNetworkPanel *panel, NMConnection *connection)
1049 {
1050         gchar *title;
1051         GtkListStore *liststore_devices;
1052         GtkTreeIter iter;
1053         NetVpn *net_vpn;
1054         const gchar *id;
1055         GtkNotebook *notebook;
1056         GtkSizeGroup *size_group;
1057 
1058         /* does already exist */
1059         id = nm_connection_get_path (connection);
1060         if (find_in_model_by_id (panel, id, NULL) != NULL)
1061                 return;
1062 
1063         /* add as a VPN object */
1064         net_vpn = g_object_new (NET_TYPE_VPN,
1065                                 "panel", panel,
1066                                 "removable", TRUE,
1067                                 "id", id,
1068                                 "connection", connection,
1069                                 "client", panel->priv->client,
1070                                 NULL);
1071         g_signal_connect_object (net_vpn, "removed",
1072                                  G_CALLBACK (object_removed_cb), panel, 0);
1073 
1074         /* add as a panel */
1075         notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->priv->builder,
1076                                                          "notebook_types"));
1077         size_group = GTK_SIZE_GROUP (gtk_builder_get_object (panel->priv->builder,
1078                                                              "sizegroup1"));
1079         net_object_add_to_notebook (NET_OBJECT (net_vpn),
1080                                     notebook,
1081                                     size_group);
1082 
1083         liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder,
1084                                             "liststore_devices"));
1085         title = g_strdup_printf (_("%s VPN"), nm_connection_get_id (connection));
1086 
1087         net_object_set_title (NET_OBJECT (net_vpn), title);
1088         gtk_list_store_append (liststore_devices, &iter);
1089         gtk_list_store_set (liststore_devices,
1090                             &iter,
1091                             PANEL_DEVICES_COLUMN_ICON, "network-vpn-symbolic",
1092                             PANEL_DEVICES_COLUMN_OBJECT, net_vpn,
1093                             -1);
1094         g_signal_connect (net_vpn, "notify::title",
1095                           G_CALLBACK (panel_net_object_notify_title_cb), panel);
1096 
1097         g_free (title);
1098         g_object_unref (net_vpn);
1099 }
1100 
1101 static void
add_connection(CcNetworkPanel * panel,NMConnection * connection)1102 add_connection (CcNetworkPanel *panel,
1103                 NMConnection *connection)
1104 {
1105         NMSettingConnection *s_con;
1106         const gchar *type, *iface;
1107 
1108         s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection,
1109                                                                   NM_TYPE_SETTING_CONNECTION));
1110         type = nm_setting_connection_get_connection_type (s_con);
1111         iface = nm_connection_get_interface_name (connection);
1112         if (g_strcmp0 (type, "vpn") != 0 && iface == NULL)
1113                 return;
1114 
1115         /* Don't add the libvirtd bridge to the UI */
1116         if (g_strcmp0 (nm_setting_connection_get_interface_name (s_con), "virbr0") == 0)
1117                 return;
1118 
1119         g_debug ("add %s/%s remote connection: %s",
1120                  type, g_type_name_from_instance ((GTypeInstance*)connection),
1121                  nm_connection_get_path (connection));
1122         if (!iface)
1123                 panel_add_vpn_device (panel, connection);
1124 }
1125 
1126 static void
notify_connection_added_cb(NMClient * client,NMRemoteConnection * connection,CcNetworkPanel * panel)1127 notify_connection_added_cb (NMClient           *client,
1128                             NMRemoteConnection *connection,
1129                             CcNetworkPanel     *panel)
1130 {
1131         add_connection (panel, NM_CONNECTION (connection));
1132 }
1133 
1134 static void
panel_check_network_manager_version(CcNetworkPanel * panel)1135 panel_check_network_manager_version (CcNetworkPanel *panel)
1136 {
1137         GtkWidget *box;
1138         GtkWidget *label;
1139         gchar *markup;
1140         const gchar *version;
1141 
1142         /* parse running version */
1143         version = nm_client_get_version (panel->priv->client);
1144         if (version == NULL) {
1145                 gtk_container_remove (GTK_CONTAINER (panel), gtk_bin_get_child (GTK_BIN (panel)));
1146 
1147                 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 20);
1148                 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1149                 gtk_widget_set_vexpand (box, TRUE);
1150                 gtk_container_add (GTK_CONTAINER (panel), box);
1151 
1152                 label = gtk_label_new (_("Oops, something has gone wrong. Please contact your software vendor."));
1153                 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
1154                 gtk_widget_set_valign (label, GTK_ALIGN_END);
1155                 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
1156 
1157                 markup = g_strdup_printf ("<small><tt>%s</tt></small>",
1158                                           _("NetworkManager needs to be running."));
1159                 label = gtk_label_new (NULL);
1160                 gtk_label_set_markup (GTK_LABEL (label), markup);
1161                 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
1162                 gtk_widget_set_valign (label, GTK_ALIGN_START);
1163                 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
1164 
1165                 gtk_widget_show_all (box);
1166                 g_free (markup);
1167         } else {
1168                 manager_running (panel->priv->client, NULL, panel);
1169         }
1170 }
1171 
1172 static void
editor_done(NetConnectionEditor * editor,gboolean success,gpointer user_data)1173 editor_done (NetConnectionEditor *editor,
1174              gboolean             success,
1175              gpointer             user_data)
1176 {
1177         g_object_unref (editor);
1178 }
1179 
1180 static void
add_connection_cb(GtkToolButton * button,CcNetworkPanel * panel)1181 add_connection_cb (GtkToolButton *button, CcNetworkPanel *panel)
1182 {
1183         NetConnectionEditor *editor;
1184         GtkWindow *toplevel;
1185 
1186         toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (panel)));
1187         editor = net_connection_editor_new (toplevel, NULL, NULL, NULL,
1188                                             panel->priv->client);
1189         g_signal_connect (editor, "done", G_CALLBACK (editor_done), panel);
1190         net_connection_editor_run (editor);
1191 }
1192 
1193 static void
remove_connection(GtkToolButton * button,CcNetworkPanel * panel)1194 remove_connection (GtkToolButton *button, CcNetworkPanel *panel)
1195 {
1196         NetObject *object;
1197 
1198         /* get current device */
1199         object = get_selected_object (panel);
1200         if (object == NULL)
1201                 return;
1202 
1203         /* delete the object */
1204         net_object_delete (object);
1205         g_object_unref (object);
1206 }
1207 
1208 static void
on_toplevel_map(GtkWidget * widget,CcNetworkPanel * panel)1209 on_toplevel_map (GtkWidget      *widget,
1210                  CcNetworkPanel *panel)
1211 {
1212         /* is the user compiling against a new version, but not running
1213          * the daemon? */
1214         panel_check_network_manager_version (panel);
1215 }
1216 
1217 static void
cc_network_panel_init(CcNetworkPanel * panel)1218 cc_network_panel_init (CcNetworkPanel *panel)
1219 {
1220         GError *error = NULL;
1221         GtkStyleContext *context;
1222         GtkTreeSelection *selection;
1223         GtkWidget *widget;
1224         GtkWidget *toplevel;
1225         GDBusConnection *system_bus;
1226         GtkCssProvider *provider;
1227         const GPtrArray *connections;
1228         guint i;
1229 
1230         panel->priv = NETWORK_PANEL_PRIVATE (panel);
1231         g_resources_register (cc_network_get_resource ());
1232 
1233         panel->priv->builder = gtk_builder_new ();
1234         gtk_builder_add_from_resource (panel->priv->builder,
1235                                        "/org/cinnamon/control-center/network/network.ui",
1236                                        &error);
1237         if (error != NULL) {
1238                 g_warning ("Could not load interface file: %s", error->message);
1239                 g_error_free (error);
1240                 return;
1241         }
1242 
1243 #ifdef HAVE_NMA_18
1244         /* some newer VPN plugins pre-require internal resources from libnma */
1245         /* this solution is really ugly, but works clean */
1246         gtk_widget_destroy (nma_cert_chooser_new ("dummy", NMA_CERT_CHOOSER_FLAG_NONE));
1247 #endif
1248 
1249         panel->priv->cancellable = g_cancellable_new ();
1250 
1251         panel->priv->treeview = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
1252                                                                     "treeview_devices"));
1253         panel_add_devices_columns (panel, GTK_TREE_VIEW (panel->priv->treeview));
1254         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview));
1255         gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1256         g_signal_connect (selection, "changed",
1257                           G_CALLBACK (nm_devices_treeview_clicked_cb), panel);
1258 
1259         widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
1260                                                      "devices_scrolledwindow"));
1261         gtk_widget_set_size_request (widget, 200, -1);
1262         context = gtk_widget_get_style_context (widget);
1263         gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
1264 
1265         widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
1266                                                      "devices_toolbar"));
1267         context = gtk_widget_get_style_context (widget);
1268         gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
1269 
1270         /* add the virtual proxy device */
1271         panel_add_proxy_device (panel);
1272 
1273         /* use NetworkManager client */
1274         panel->priv->client = nm_client_new (NULL, NULL);
1275         g_signal_connect (panel->priv->client, "notify::nm-running" ,
1276                           G_CALLBACK (manager_running), panel);
1277         g_signal_connect (panel->priv->client, "notify::active-connections",
1278                           G_CALLBACK (active_connections_changed), panel);
1279         g_signal_connect (panel->priv->client, "device-added",
1280                           G_CALLBACK (device_added_cb), panel);
1281         g_signal_connect (panel->priv->client, "device-removed",
1282                           G_CALLBACK (device_removed_cb), panel);
1283 
1284 #ifdef BUILD_MODEM
1285         /* Setup ModemManager client */
1286         system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
1287         if (system_bus == NULL) {
1288                 g_warning ("Error connecting to system D-Bus: %s",
1289                            error->message);
1290                 g_clear_error (&error);
1291         } else {
1292                 panel->priv->modem_manager = mm_manager_new_sync (system_bus,
1293                                                                   G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
1294                                                                   NULL,
1295                                                                   &error);
1296                 if (panel->priv->modem_manager == NULL) {
1297                         g_warning ("Error connecting to ModemManager: %s",
1298                                    error->message);
1299                         g_clear_error (&error);
1300                 }
1301                 g_object_unref (system_bus);
1302         }
1303 #else
1304         panel->priv->modem_manager = NULL;
1305 #endif
1306 
1307         widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
1308                                                      "add_toolbutton"));
1309         g_signal_connect (widget, "clicked",
1310                           G_CALLBACK (add_connection_cb), panel);
1311 
1312         /* disable for now, until we actually show removable connections */
1313         widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
1314                                                      "remove_toolbutton"));
1315         g_signal_connect (widget, "clicked",
1316                           G_CALLBACK (remove_connection), panel);
1317 
1318         /* add remote settings such as VPN settings as virtual devices */
1319         g_signal_connect (panel->priv->client, NM_CLIENT_CONNECTION_ADDED,
1320                           G_CALLBACK (notify_connection_added_cb), panel);
1321 
1322         toplevel = gtk_widget_get_toplevel (GTK_WIDGET (panel));
1323         g_signal_connect_after (toplevel, "map", G_CALLBACK (on_toplevel_map), panel);
1324 
1325         /* hide implementation details */
1326         widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
1327                                                      "notebook_types"));
1328         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
1329 
1330         widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
1331                                                      "vbox1"));
1332         gtk_container_add (GTK_CONTAINER (panel), widget);
1333 
1334         provider = gtk_css_provider_new ();
1335         gtk_css_provider_load_from_data (provider, ".circular-button { border-radius: 20px; -gtk-outline-radius: 20px; }", -1, NULL);
1336         gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
1337                                                    GTK_STYLE_PROVIDER (provider),
1338                                                    GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1339         g_object_unref (provider);
1340 
1341         /* Cold-plug existing connections */
1342         connections = nm_client_get_connections (panel->priv->client);
1343         if (connections) {
1344                 for (i = 0; i < connections->len; i++)
1345                         add_connection (panel, connections->pdata[i]);
1346         }
1347 
1348         g_debug ("Calling handle_argv() after cold-plugging connections");
1349         handle_argv (panel);
1350 }
1351 
1352 void
cc_network_panel_register(GIOModule * module)1353 cc_network_panel_register (GIOModule *module)
1354 {
1355         textdomain (GETTEXT_PACKAGE);
1356         bindtextdomain (GETTEXT_PACKAGE, "/usr/share/locale");
1357         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1358         cc_network_panel_register_type (G_TYPE_MODULE (module));
1359         g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
1360                                         CC_TYPE_NETWORK_PANEL,
1361                                         "network", 0);
1362 }
1363