summaryrefslogtreecommitdiffstats
path: root/gnome-initial-setup/pages/network
diff options
context:
space:
mode:
Diffstat (limited to 'gnome-initial-setup/pages/network')
-rw-r--r--gnome-initial-setup/pages/network/gis-network-page.c828
-rw-r--r--gnome-initial-setup/pages/network/gis-network-page.h55
-rw-r--r--gnome-initial-setup/pages/network/gis-network-page.ui99
-rw-r--r--gnome-initial-setup/pages/network/meson.build12
-rw-r--r--gnome-initial-setup/pages/network/network-dialogs.c515
-rw-r--r--gnome-initial-setup/pages/network/network-dialogs.h41
-rw-r--r--gnome-initial-setup/pages/network/network.gresource.xml6
7 files changed, 1556 insertions, 0 deletions
diff --git a/gnome-initial-setup/pages/network/gis-network-page.c b/gnome-initial-setup/pages/network/gis-network-page.c
new file mode 100644
index 0000000..859288f
--- /dev/null
+++ b/gnome-initial-setup/pages/network/gis-network-page.c
@@ -0,0 +1,828 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+/* Network page {{{1 */
+
+#define PAGE_ID "network"
+
+#include "config.h"
+#include "network-resources.h"
+#include "gis-network-page.h"
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "network-dialogs.h"
+
+#include "gis-page-header.h"
+
+typedef enum {
+ NM_AP_SEC_UNKNOWN,
+ NM_AP_SEC_NONE,
+ NM_AP_SEC_WEP,
+ NM_AP_SEC_WPA,
+ NM_AP_SEC_WPA2
+} NMAccessPointSecurity;
+
+struct _GisNetworkPagePrivate {
+ GtkWidget *network_list;
+ GtkWidget *no_network_label;
+ GtkWidget *no_network_spinner;
+ GtkWidget *turn_on_label;
+ GtkWidget *turn_on_switch;
+
+ NMClient *nm_client;
+ NMDevice *nm_device;
+ gboolean refreshing;
+ GtkSizeGroup *icons;
+
+ guint refresh_timeout_id;
+
+ /* TRUE if the page has ever been shown to the user. */
+ gboolean ever_shown;
+};
+typedef struct _GisNetworkPagePrivate GisNetworkPagePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GisNetworkPage, gis_network_page, GIS_TYPE_PAGE);
+
+static GPtrArray *
+get_strongest_unique_aps (const GPtrArray *aps)
+{
+ GBytes *ssid;
+ GBytes *ssid_tmp;
+ GPtrArray *unique = NULL;
+ gboolean add_ap;
+ guint i;
+ guint j;
+ NMAccessPoint *ap;
+ NMAccessPoint *ap_tmp;
+
+ /* we will have multiple entries for typical hotspots,
+ * just keep the one with the strongest signal
+ */
+ unique = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ if (aps == NULL)
+ goto out;
+
+ for (i = 0; i < aps->len; i++) {
+ ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i));
+ ssid = nm_access_point_get_ssid (ap);
+ add_ap = TRUE;
+
+ if (!ssid)
+ continue;
+
+ /* get already added list */
+ for (j = 0; j < unique->len; j++) {
+ ap_tmp = NM_ACCESS_POINT (g_ptr_array_index (unique, j));
+ ssid_tmp = nm_access_point_get_ssid (ap_tmp);
+
+ /* is this the same type and data? */
+ if (ssid_tmp &&
+ nm_utils_same_ssid (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid),
+ g_bytes_get_data (ssid_tmp, NULL), g_bytes_get_size (ssid_tmp), TRUE)) {
+ /* the new access point is stronger */
+ if (nm_access_point_get_strength (ap) >
+ nm_access_point_get_strength (ap_tmp)) {
+ g_ptr_array_remove (unique, ap_tmp);
+ add_ap = TRUE;
+ } else {
+ add_ap = FALSE;
+ }
+ break;
+ }
+ }
+ if (add_ap) {
+ g_ptr_array_add (unique, g_object_ref (ap));
+ }
+ }
+
+ out:
+ return unique;
+}
+
+static guint
+get_access_point_security (NMAccessPoint *ap)
+{
+ NM80211ApFlags flags;
+ NM80211ApSecurityFlags wpa_flags;
+ NM80211ApSecurityFlags rsn_flags;
+ guint type;
+
+ flags = nm_access_point_get_flags (ap);
+ wpa_flags = nm_access_point_get_wpa_flags (ap);
+ rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+ if (!(flags & NM_802_11_AP_FLAGS_PRIVACY) &&
+ wpa_flags == NM_802_11_AP_SEC_NONE &&
+ rsn_flags == NM_802_11_AP_SEC_NONE)
+ type = NM_AP_SEC_NONE;
+ else if ((flags & NM_802_11_AP_FLAGS_PRIVACY) &&
+ wpa_flags == NM_802_11_AP_SEC_NONE &&
+ rsn_flags == NM_802_11_AP_SEC_NONE)
+ type = NM_AP_SEC_WEP;
+ else if (!(flags & NM_802_11_AP_FLAGS_PRIVACY) &&
+ wpa_flags != NM_802_11_AP_SEC_NONE &&
+ rsn_flags != NM_802_11_AP_SEC_NONE)
+ type = NM_AP_SEC_WPA;
+ else
+ type = NM_AP_SEC_WPA2;
+
+ return type;
+}
+
+static gint
+ap_sort (GtkListBoxRow *a,
+ GtkListBoxRow *b,
+ gpointer data)
+{
+ GtkWidget *wa, *wb;
+ guint sa, sb;
+
+ wa = gtk_list_box_row_get_child (a);
+ wb = gtk_list_box_row_get_child (b);
+
+ sa = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (wa), "strength"));
+ sb = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (wb), "strength"));
+ if (sa > sb) return -1;
+ if (sb > sa) return 1;
+
+ return 0;
+}
+
+static void
+add_access_point (GisNetworkPage *page, NMAccessPoint *ap, NMAccessPoint *active)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ GBytes *ssid;
+ GBytes *ssid_active = NULL;
+ gchar *ssid_text;
+ const gchar *object_path;
+ gboolean activated, activating;
+ guint security;
+ guint strength;
+ const gchar *icon_name;
+ GtkWidget *row;
+ GtkWidget *widget;
+ GtkWidget *grid;
+ GtkWidget *state_widget = NULL;
+
+ ssid = nm_access_point_get_ssid (ap);
+ object_path = nm_object_get_path (NM_OBJECT (ap));
+
+ if (ssid == NULL)
+ return;
+ ssid_text = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid));
+
+ if (active)
+ ssid_active = nm_access_point_get_ssid (active);
+ if (ssid_active && nm_utils_same_ssid (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid),
+ g_bytes_get_data (ssid_active, NULL), g_bytes_get_size (ssid_active), TRUE)) {
+ switch (nm_device_get_state (priv->nm_device))
+ {
+ case NM_DEVICE_STATE_PREPARE:
+ case NM_DEVICE_STATE_CONFIG:
+ case NM_DEVICE_STATE_NEED_AUTH:
+ case NM_DEVICE_STATE_IP_CONFIG:
+ case NM_DEVICE_STATE_SECONDARIES:
+ activated = FALSE;
+ activating = TRUE;
+ break;
+ case NM_DEVICE_STATE_ACTIVATED:
+ activated = TRUE;
+ activating = FALSE;
+ break;
+ default:
+ activated = FALSE;
+ activating = FALSE;
+ break;
+ }
+ } else {
+ activated = FALSE;
+ activating = FALSE;
+ }
+
+ security = get_access_point_security (ap);
+ strength = nm_access_point_get_strength (ap);
+
+ row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_widget_set_margin_start (row, 12);
+ gtk_widget_set_margin_end (row, 12);
+ widget = gtk_label_new (ssid_text);
+ gtk_widget_set_margin_top (widget, 12);
+ gtk_widget_set_margin_bottom (widget, 12);
+ gtk_box_append (GTK_BOX (row), widget);
+
+ if (activated) {
+ state_widget = gtk_image_new_from_icon_name ("object-select-symbolic");
+ } else if (activating) {
+ state_widget = gtk_spinner_new ();
+ gtk_spinner_start (GTK_SPINNER (state_widget));
+ }
+
+ if (state_widget) {
+ gtk_widget_set_halign (state_widget, GTK_ALIGN_START);
+ gtk_widget_set_valign (state_widget, GTK_ALIGN_CENTER);
+ gtk_widget_set_hexpand (state_widget, TRUE);
+ gtk_box_append (GTK_BOX (row), state_widget);
+ }
+
+ grid = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
+ gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
+ gtk_widget_set_valign (grid, GTK_ALIGN_CENTER);
+ gtk_size_group_add_widget (priv->icons, grid);
+ gtk_box_append (GTK_BOX (row), grid);
+
+ if (security != NM_AP_SEC_UNKNOWN &&
+ security != NM_AP_SEC_NONE) {
+ widget = gtk_image_new_from_icon_name ("network-wireless-encrypted-symbolic");
+ gtk_grid_attach (GTK_GRID (grid), widget, 0, 0, 1, 1);
+ }
+
+ if (strength < 20)
+ icon_name = "network-wireless-signal-none-symbolic";
+ else if (strength < 40)
+ icon_name = "network-wireless-signal-weak-symbolic";
+ else if (strength < 50)
+ icon_name = "network-wireless-signal-ok-symbolic";
+ else if (strength < 80)
+ icon_name = "network-wireless-signal-good-symbolic";
+ else
+ icon_name = "network-wireless-signal-excellent-symbolic";
+ widget = gtk_image_new_from_icon_name (icon_name);
+ gtk_widget_set_halign (widget, GTK_ALIGN_END);
+ gtk_grid_attach (GTK_GRID (grid), widget, 1, 0, 1, 1);
+
+ /* if this connection is the active one or is being activated, then make sure
+ * it's sorted before all others */
+ if (activating || activated)
+ strength = G_MAXUINT;
+
+ g_object_set_data (G_OBJECT (row), "object-path", (gpointer) object_path);
+ g_object_set_data (G_OBJECT (row), "ssid", (gpointer) ssid);
+ g_object_set_data (G_OBJECT (row), "strength", GUINT_TO_POINTER (strength));
+
+ gtk_list_box_append (GTK_LIST_BOX (priv->network_list), row);
+}
+
+static void
+add_access_point_other (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ GtkWidget *row;
+ GtkWidget *widget;
+
+ row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_widget_set_margin_start (row, 12);
+ gtk_widget_set_margin_end (row, 12);
+ widget = gtk_label_new (C_("Wireless access point", "Other…"));
+ gtk_widget_set_margin_top (widget, 12);
+ gtk_widget_set_margin_bottom (widget, 12);
+ gtk_box_append (GTK_BOX (row), widget);
+
+ g_object_set_data (G_OBJECT (row), "object-path", "ap-other...");
+ g_object_set_data (G_OBJECT (row), "strength", GUINT_TO_POINTER (0));
+
+ gtk_list_box_append (GTK_LIST_BOX (priv->network_list), row);
+}
+
+static gboolean refresh_wireless_list (GisNetworkPage *page);
+
+static void
+cancel_periodic_refresh (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+
+ if (priv->refresh_timeout_id == 0)
+ return;
+
+ g_debug ("Stopping periodic/scheduled Wi-Fi list refresh");
+
+ g_clear_handle_id (&priv->refresh_timeout_id, g_source_remove);
+}
+
+static gboolean
+refresh_again (gpointer user_data)
+{
+ GisNetworkPage *page = GIS_NETWORK_PAGE (user_data);
+ refresh_wireless_list (page);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+start_periodic_refresh (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ static const guint periodic_wifi_refresh_timeout_sec = 10;
+
+ cancel_periodic_refresh (page);
+
+ g_debug ("Starting periodic Wi-Fi list refresh (every %u secs)",
+ periodic_wifi_refresh_timeout_sec);
+ priv->refresh_timeout_id = g_timeout_add_seconds (periodic_wifi_refresh_timeout_sec,
+ refresh_again, page);
+}
+
+static gboolean
+refresh_wireless_list (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ NMAccessPoint *active_ap = NULL;
+ NMAccessPoint *ap;
+ const GPtrArray *aps;
+ GPtrArray *unique_aps;
+ GtkWidget *child;
+ guint i;
+ gboolean enabled;
+
+ g_debug ("Refreshing Wi-Fi networks list");
+
+ priv->refreshing = TRUE;
+
+ g_assert (NM_IS_DEVICE_WIFI (priv->nm_device));
+
+ cancel_periodic_refresh (page);
+
+ active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (priv->nm_device));
+
+ while ((child = gtk_widget_get_first_child (priv->network_list)) != NULL)
+ gtk_list_box_remove (GTK_LIST_BOX (priv->network_list), child);
+
+ aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (priv->nm_device));
+ enabled = nm_client_wireless_get_enabled (priv->nm_client);
+
+ if (aps == NULL || aps->len == 0) {
+ gboolean hw_enabled;
+
+ hw_enabled = nm_client_wireless_hardware_get_enabled (priv->nm_client);
+
+ if (!enabled || !hw_enabled) {
+ gtk_label_set_text (GTK_LABEL (priv->no_network_label), _("Wireless networking is disabled"));
+ gtk_widget_show (priv->no_network_label);
+ gtk_widget_hide (priv->no_network_spinner);
+
+ gtk_widget_set_visible (priv->turn_on_label, hw_enabled);
+ gtk_widget_set_visible (priv->turn_on_switch, hw_enabled);
+ } else {
+ gtk_label_set_text (GTK_LABEL (priv->no_network_label), _("Checking for available wireless networks"));
+ gtk_widget_show (priv->no_network_spinner);
+ gtk_widget_show (priv->no_network_label);
+ gtk_widget_hide (priv->turn_on_label);
+ gtk_widget_hide (priv->turn_on_switch);
+ }
+
+ gtk_widget_hide (priv->network_list);
+ goto out;
+
+ } else {
+ gtk_widget_hide (priv->no_network_spinner);
+ gtk_widget_hide (priv->no_network_label);
+ gtk_widget_hide (priv->turn_on_label);
+ gtk_widget_hide (priv->turn_on_switch);
+ gtk_widget_show (priv->network_list);
+ }
+
+ unique_aps = get_strongest_unique_aps (aps);
+ for (i = 0; i < unique_aps->len; i++) {
+ ap = NM_ACCESS_POINT (g_ptr_array_index (unique_aps, i));
+ add_access_point (page, ap, active_ap);
+ }
+ g_ptr_array_unref (unique_aps);
+ add_access_point_other (page);
+
+ out:
+
+ if (enabled)
+ start_periodic_refresh (page);
+
+ priv->refreshing = FALSE;
+
+ return G_SOURCE_REMOVE;
+}
+
+/* Avoid repeated calls to refreshing the wireless list by making it refresh at
+ * most once per second */
+static void
+schedule_refresh_wireless_list (GisNetworkPage *page)
+{
+ static const guint refresh_wireless_list_timeout_sec = 1;
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+
+ cancel_periodic_refresh (page);
+
+ g_debug ("Delaying Wi-Fi list refresh (for %u sec)",
+ refresh_wireless_list_timeout_sec);
+
+ priv->refresh_timeout_id = g_timeout_add_seconds (refresh_wireless_list_timeout_sec,
+ (GSourceFunc) refresh_wireless_list,
+ page);
+}
+
+static void
+connection_activate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ NMClient *client = NM_CLIENT (object);
+ NMActiveConnection *connection = NULL;
+ g_autoptr(GError) error = NULL;
+
+ connection = nm_client_activate_connection_finish (client, result, &error);
+ if (connection != NULL) {
+ g_clear_object (&connection);
+ } else {
+ /* failed to activate */
+ g_warning ("Failed to activate a connection: %s", error->message);
+ }
+}
+
+static void
+connection_add_activate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ NMClient *client = NM_CLIENT (object);
+ NMActiveConnection *connection = NULL;
+ g_autoptr(GError) error = NULL;
+
+ connection = nm_client_add_and_activate_connection_finish (client, result, &error);
+ if (connection != NULL) {
+ g_clear_object (&connection);
+ } else {
+ /* failed to activate */
+ g_warning ("Failed to add and activate a connection: %s", error->message);
+ }
+}
+
+static void
+connect_to_hidden_network (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (page));
+
+ cc_network_panel_connect_to_hidden_network (GTK_WIDGET (root), priv->nm_client);
+}
+
+static void
+row_activated (GtkListBox *box,
+ GtkListBoxRow *row,
+ GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ gchar *object_path;
+ const GPtrArray *list;
+ GPtrArray *filtered;
+ NMConnection *connection;
+ NMConnection *connection_to_activate;
+ NMSettingWireless *setting;
+ GBytes *ssid;
+ GBytes *ssid_target;
+ GtkWidget *child;
+ int i;
+
+ if (priv->refreshing)
+ return;
+
+ child = gtk_list_box_row_get_child (row);
+ object_path = g_object_get_data (G_OBJECT (child), "object-path");
+ ssid_target = g_object_get_data (G_OBJECT (child), "ssid");
+
+ if (g_strcmp0 (object_path, "ap-other...") == 0) {
+ connect_to_hidden_network (page);
+ goto out;
+ }
+
+ list = nm_client_get_connections (priv->nm_client);
+ filtered = nm_device_filter_connections (priv->nm_device, list);
+
+ connection_to_activate = NULL;
+
+ for (i = 0; i < filtered->len; i++) {
+ connection = NM_CONNECTION (filtered->pdata[i]);
+ setting = nm_connection_get_setting_wireless (connection);
+ if (!NM_IS_SETTING_WIRELESS (setting))
+ continue;
+
+ ssid = nm_setting_wireless_get_ssid (setting);
+ if (ssid == NULL)
+ continue;
+
+ if (nm_utils_same_ssid (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid),
+ g_bytes_get_data (ssid_target, NULL), g_bytes_get_size (ssid_target), TRUE)) {
+ connection_to_activate = connection;
+ break;
+ }
+ }
+ g_ptr_array_unref (filtered);
+
+ if (connection_to_activate != NULL) {
+ nm_client_activate_connection_async (priv->nm_client,
+ connection_to_activate,
+ priv->nm_device, NULL,
+ NULL,
+ connection_activate_cb, page);
+ return;
+ }
+
+ nm_client_add_and_activate_connection_async (priv->nm_client,
+ NULL,
+ priv->nm_device, object_path,
+ NULL,
+ connection_add_activate_cb, page);
+
+ out:
+ schedule_refresh_wireless_list (page);
+}
+
+static void
+connection_state_changed (NMActiveConnection *c, GParamSpec *pspec, GisNetworkPage *page)
+{
+ schedule_refresh_wireless_list (page);
+}
+
+static void
+active_connections_changed (NMClient *client, GParamSpec *pspec, GisNetworkPage *page)
+{
+ const GPtrArray *connections;
+ guint i;
+
+ connections = nm_client_get_active_connections (client);
+ for (i = 0; connections && (i < connections->len); i++) {
+ NMActiveConnection *connection;
+
+ connection = g_ptr_array_index (connections, i);
+ if (!g_object_get_data (G_OBJECT (connection), "has-state-changed-handler")) {
+ g_signal_connect (connection, "notify::state",
+ G_CALLBACK (connection_state_changed), page);
+ g_object_set_data (G_OBJECT (connection), "has-state-changed-handler", GINT_TO_POINTER (1));
+ }
+ }
+}
+
+static void
+sync_complete (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ gboolean has_device;
+ gboolean activated;
+ gboolean visible;
+
+ has_device = priv->nm_device != NULL;
+ activated = priv->nm_device != NULL
+ && nm_device_get_state (priv->nm_device) == NM_DEVICE_STATE_ACTIVATED;
+
+ if (priv->ever_shown) {
+ visible = TRUE;
+ } else if (!has_device) {
+ g_debug ("No network device found, hiding network page");
+ visible = FALSE;
+ } else if (activated) {
+ g_debug ("Activated network device found, hiding network page");
+ visible = FALSE;
+ } else {
+ visible = TRUE;
+ }
+
+ gis_page_set_complete (GIS_PAGE (page), activated);
+ gtk_widget_set_visible (GTK_WIDGET (page), visible);
+
+ if (has_device)
+ schedule_refresh_wireless_list (page);
+}
+
+static void
+device_state_changed (GObject *object, GParamSpec *param, GisNetworkPage *page)
+{
+ sync_complete (page);
+}
+
+static void
+find_best_device (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ const GPtrArray *devices;
+ guint i;
+
+ /* FIXME: deal with multiple devices and devices being removed */
+ if (priv->nm_device != NULL) {
+ g_debug ("Already showing network device %s",
+ nm_device_get_description (priv->nm_device));
+ return;
+ }
+
+ devices = nm_client_get_devices (priv->nm_client);
+ g_return_if_fail (devices != NULL);
+ for (i = 0; i < devices->len; i++) {
+ NMDevice *device = g_ptr_array_index (devices, i);
+
+ if (!nm_device_get_managed (device))
+ continue;
+
+ if (nm_device_get_device_type (device) == NM_DEVICE_TYPE_WIFI) {
+ /* FIXME deal with multiple, dynamic devices */
+ priv->nm_device = g_object_ref (device);
+ g_debug ("Showing network device %s",
+ nm_device_get_description (priv->nm_device));
+
+ g_signal_connect (priv->nm_device, "notify::state",
+ G_CALLBACK (device_state_changed), page);
+ g_signal_connect (priv->nm_client, "notify::active-connections",
+ G_CALLBACK (active_connections_changed), page);
+
+ break;
+ }
+ }
+
+ sync_complete (page);
+}
+static void
+device_notify_managed (NMDevice *device,
+ GParamSpec *param,
+ void *user_data)
+{
+ GisNetworkPage *page = GIS_NETWORK_PAGE (user_data);
+
+ find_best_device (page);
+}
+
+static void
+client_device_added (NMClient *client,
+ NMDevice *device,
+ void *user_data)
+{
+ GisNetworkPage *page = GIS_NETWORK_PAGE (user_data);
+
+ g_signal_connect_object (device,
+ "notify::managed",
+ G_CALLBACK (device_notify_managed),
+ G_OBJECT (page),
+ 0);
+
+ find_best_device (page);
+}
+
+static void
+client_device_removed (NMClient *client,
+ NMDevice *device,
+ void *user_data)
+{
+ GisNetworkPage *page = GIS_NETWORK_PAGE (user_data);
+
+ /* TODO: reset page if priv->nm_device == device */
+ g_signal_handlers_disconnect_by_func (device, device_notify_managed, page);
+
+ find_best_device (page);
+}
+
+static void
+monitor_network_devices (GisNetworkPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ const GPtrArray *devices;
+ guint i;
+
+ g_assert (priv->nm_client != NULL);
+ devices = nm_client_get_devices (priv->nm_client);
+ g_return_if_fail (devices != NULL);
+ for (i = 0; devices != NULL && i < devices->len; i++) {
+ NMDevice *device = g_ptr_array_index (devices, i);
+
+ g_signal_connect_object (device,
+ "notify::managed",
+ G_CALLBACK (device_notify_managed),
+ G_OBJECT (page),
+ 0);
+ }
+
+ g_signal_connect_object (priv->nm_client,
+ "device-added",
+ G_CALLBACK (client_device_added),
+ G_OBJECT (page),
+ 0);
+ g_signal_connect_object (priv->nm_client,
+ "device-removed",
+ G_CALLBACK (client_device_removed),
+ G_OBJECT (page),
+ 0);
+
+ find_best_device (page);
+}
+
+static void
+gis_network_page_constructed (GObject *object)
+{
+ GisNetworkPage *page = GIS_NETWORK_PAGE (object);
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+ g_autoptr(GError) error = NULL;
+
+ G_OBJECT_CLASS (gis_network_page_parent_class)->constructed (object);
+
+ gis_page_set_skippable (GIS_PAGE (page), TRUE);
+
+ priv->ever_shown = g_getenv ("GIS_ALWAYS_SHOW_NETWORK_PAGE") != NULL;
+ priv->icons = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ gtk_list_box_set_selection_mode (GTK_LIST_BOX (priv->network_list), GTK_SELECTION_NONE);
+ gtk_list_box_set_sort_func (GTK_LIST_BOX (priv->network_list), ap_sort, NULL, NULL);
+ g_signal_connect (priv->network_list, "row-activated",
+ G_CALLBACK (row_activated), page);
+
+ priv->nm_client = nm_client_new (NULL, &error);
+ if (!priv->nm_client) {
+ g_warning ("Can't create NetworkManager client, hiding network page: %s",
+ error->message);
+ sync_complete (page);
+ return;
+ }
+
+ g_object_bind_property (priv->nm_client, "wireless-enabled",
+ priv->turn_on_switch, "active",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+ monitor_network_devices (page);
+}
+
+static void
+gis_network_page_dispose (GObject *object)
+{
+ GisNetworkPage *page = GIS_NETWORK_PAGE (object);
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
+
+ g_clear_object (&priv->nm_client);
+ g_clear_object (&priv->nm_device);
+ g_clear_object (&priv->icons);
+
+ cancel_periodic_refresh (page);
+
+ G_OBJECT_CLASS (gis_network_page_parent_class)->dispose (object);
+}
+
+static void
+gis_network_page_locale_changed (GisPage *page)
+{
+ gis_page_set_title (GIS_PAGE (page), _("Network"));
+}
+
+static void
+gis_network_page_shown (GisPage *page)
+{
+ GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (GIS_NETWORK_PAGE (page));
+
+ priv->ever_shown = TRUE;
+}
+
+static void
+gis_network_page_class_init (GisNetworkPageClass *klass)
+{
+ GisPageClass *page_class = GIS_PAGE_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/initial-setup/gis-network-page.ui");
+
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisNetworkPage, network_list);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisNetworkPage, no_network_label);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisNetworkPage, no_network_spinner);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisNetworkPage, turn_on_label);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisNetworkPage, turn_on_switch);
+
+ page_class->page_id = PAGE_ID;
+ page_class->locale_changed = gis_network_page_locale_changed;
+ page_class->shown = gis_network_page_shown;
+ object_class->constructed = gis_network_page_constructed;
+ object_class->dispose = gis_network_page_dispose;
+}
+
+static void
+gis_network_page_init (GisNetworkPage *page)
+{
+ g_resources_register (network_get_resource ());
+ g_type_ensure (GIS_TYPE_PAGE_HEADER);
+
+ gtk_widget_init_template (GTK_WIDGET (page));
+}
+
+GisPage *
+gis_prepare_network_page (GisDriver *driver)
+{
+ return g_object_new (GIS_TYPE_NETWORK_PAGE,
+ "driver", driver,
+ NULL);
+}
diff --git a/gnome-initial-setup/pages/network/gis-network-page.h b/gnome-initial-setup/pages/network/gis-network-page.h
new file mode 100644
index 0000000..172b7d1
--- /dev/null
+++ b/gnome-initial-setup/pages/network/gis-network-page.h
@@ -0,0 +1,55 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#ifndef __GIS_NETWORK_PAGE_H__
+#define __GIS_NETWORK_PAGE_H__
+
+#include "gnome-initial-setup.h"
+
+G_BEGIN_DECLS
+
+#define GIS_TYPE_NETWORK_PAGE (gis_network_page_get_type ())
+#define GIS_NETWORK_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIS_TYPE_NETWORK_PAGE, GisNetworkPage))
+#define GIS_NETWORK_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIS_TYPE_NETWORK_PAGE, GisNetworkPageClass))
+#define GIS_IS_NETWORK_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIS_TYPE_NETWORK_PAGE))
+#define GIS_IS_NETWORK_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIS_TYPE_NETWORK_PAGE))
+#define GIS_NETWORK_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIS_TYPE_NETWORK_PAGE, GisNetworkPageClass))
+
+typedef struct _GisNetworkPage GisNetworkPage;
+typedef struct _GisNetworkPageClass GisNetworkPageClass;
+
+struct _GisNetworkPage
+{
+ GisPage parent;
+};
+
+struct _GisNetworkPageClass
+{
+ GisPageClass parent_class;
+};
+
+GType gis_network_page_get_type (void);
+
+GisPage *gis_prepare_network_page (GisDriver *driver);
+
+G_END_DECLS
+
+#endif /* __GIS_NETWORK_PAGE_H__ */
diff --git a/gnome-initial-setup/pages/network/gis-network-page.ui b/gnome-initial-setup/pages/network/gis-network-page.ui
new file mode 100644
index 0000000..2bda59c
--- /dev/null
+++ b/gnome-initial-setup/pages/network/gis-network-page.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GisNetworkPage" parent="GisPage">
+ <child>
+ <object class="AdwPreferencesPage">
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="orientation">vertical</property>
+ <property name="margin_bottom">32</property>
+ <child>
+ <object class="GisPageHeader" id="header">
+ <property name="margin_top">24</property>
+ <property name="title" translatable="yes">Wi-Fi</property>
+ <property name="subtitle" translatable="yes">Connecting to the internet helps you get new apps, information, and other upgrades. It also helps set the time and your location automatically.</property>
+ <property name="icon_name">network-wireless-symbolic</property>
+ <property name="show_icon" bind-source="GisNetworkPage" bind-property="small-screen" bind-flags="invert-boolean|sync-create"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="network_list">
+ <property name="valign">start</property>
+ <property name="vexpand">True</property>
+ <property name="margin-top">18</property>
+ <style>
+ <class name="boxed-list" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkGrid" id="no_network_grid">
+ <property name="margin_top">18</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="row-spacing">10</property>
+ <child>
+ <object class="GtkSpinner" id="no_network_spinner">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin_start">6</property>
+ <property name="margin_end">6</property>
+ <property name="spinning">True</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="column-span">1</property>
+ <property name="row-span">1</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="no_network_label">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">No wireless available</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">0</property>
+ <property name="column-span">2</property>
+ <property name="row-span">1</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="turn_on_label">
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">Turn On</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">1</property>
+ <property name="column-span">1</property>
+ <property name="row-span">1</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="turn_on_switch">
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <layout>
+ <property name="column">2</property>
+ <property name="row">1</property>
+ <property name="column-span">1</property>
+ <property name="row-span">1</property>
+ </layout>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/gnome-initial-setup/pages/network/meson.build b/gnome-initial-setup/pages/network/meson.build
new file mode 100644
index 0000000..2c0f2a7
--- /dev/null
+++ b/gnome-initial-setup/pages/network/meson.build
@@ -0,0 +1,12 @@
+sources += gnome.compile_resources(
+ 'network-resources',
+ files('network.gresource.xml'),
+ c_name: 'network'
+)
+
+sources += files(
+ 'network-dialogs.c',
+ 'network-dialogs.h',
+ 'gis-network-page.c',
+ 'gis-network-page.h'
+)
diff --git a/gnome-initial-setup/pages/network/network-dialogs.c b/gnome-initial-setup/pages/network/network-dialogs.c
new file mode 100644
index 0000000..9018eac
--- /dev/null
+++ b/gnome-initial-setup/pages/network/network-dialogs.c
@@ -0,0 +1,515 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Portions of this code were taken from network-manager-applet.
+ * Copyright 2008 - 2011 Red Hat, Inc.
+ */
+
+#include <gtk/gtk.h>
+#include <NetworkManager.h>
+#include <nma-wifi-dialog.h>
+#include <nma-mobile-wizard.h>
+
+typedef struct {
+ NMClient *client;
+} WirelessDialogClosure;
+
+typedef struct {
+ NMClient *client;
+ NMDevice *device;
+} MobileDialogClosure;
+
+static void
+wireless_dialog_closure_closure_notify (gpointer data,
+ GClosure *gclosure)
+{
+ WirelessDialogClosure *closure = data;
+ g_object_unref (closure->client);
+
+ g_slice_free (WirelessDialogClosure, data);
+}
+
+static void
+mobile_dialog_closure_free (gpointer data)
+{
+ MobileDialogClosure *closure = data;
+ g_object_unref (closure->client);
+ g_object_unref (closure->device);
+
+ g_slice_free (MobileDialogClosure, data);
+}
+
+static gboolean
+wifi_can_create_wifi_network (NMClient *client)
+{
+ NMClientPermissionResult perm;
+
+ /* FIXME: check WIFI_SHARE_PROTECTED too, and make the wireless dialog
+ * handle the permissions as well so that admins can restrict open network
+ * creation separately from protected network creation.
+ */
+ perm = nm_client_get_permission_result (client, NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN);
+ if (perm == NM_CLIENT_PERMISSION_RESULT_YES || perm == NM_CLIENT_PERMISSION_RESULT_AUTH)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+activate_existing_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ NMClient *client = NM_CLIENT (object);
+ NMActiveConnection *connection;
+ GError *error = NULL;
+
+ connection = nm_client_activate_connection_finish (client, result, &error);
+ if (connection) {
+ g_object_unref (connection);
+ } else {
+ g_warning ("Failed to activate connection: (%d) %s", error->code, error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+activate_new_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ NMClient *client = NM_CLIENT (object);
+ NMActiveConnection *connection;
+ GError *error = NULL;
+
+ connection = nm_client_add_and_activate_connection_finish (client, result, &error);
+ if (connection) {
+ g_object_unref (connection);
+ } else {
+ g_warning ("Failed to add new connection: (%d) %s", error->code, error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+wireless_dialog_response_cb (GtkDialog *foo,
+ gint response,
+ gpointer user_data)
+{
+ NMAWifiDialog *dialog = NMA_WIFI_DIALOG (foo);
+ WirelessDialogClosure *closure = user_data;
+ NMConnection *connection, *fuzzy_match = NULL;
+ NMDevice *device;
+ NMAccessPoint *ap;
+ const GPtrArray *all;
+ int i;
+
+ if (response != GTK_RESPONSE_OK)
+ goto done;
+
+ /* nma_wifi_dialog_get_connection() returns a connection with the
+ * refcount incremented, so the caller must remember to unref it.
+ */
+ connection = nma_wifi_dialog_get_connection (dialog, &device, &ap);
+ g_assert (connection);
+ g_assert (device);
+
+ /* Find a similar connection and use that instead */
+ all = nm_client_get_connections (closure->client);
+ for (i = 0; i < all->len; i++) {
+ if (nm_connection_compare (connection,
+ NM_CONNECTION (all->pdata[i]),
+ (NM_SETTING_COMPARE_FLAG_FUZZY | NM_SETTING_COMPARE_FLAG_IGNORE_ID))) {
+ fuzzy_match = NM_CONNECTION (all->pdata[i]);
+ break;
+ }
+ }
+
+ if (fuzzy_match) {
+ nm_client_activate_connection_async (closure->client,
+ fuzzy_match,
+ device,
+ ap ? nm_object_get_path (NM_OBJECT (ap)) : NULL,
+ NULL,
+ activate_existing_cb,
+ NULL);
+ } else {
+ NMSetting *s_con;
+ NMSettingWireless *s_wifi;
+ const char *mode = NULL;
+
+ /* Entirely new connection */
+
+ /* Don't autoconnect adhoc networks by default for now */
+ s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+ if (s_wifi)
+ mode = nm_setting_wireless_get_mode (s_wifi);
+ if (g_strcmp0 (mode, "adhoc") == 0) {
+ s_con = nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+ if (!s_con) {
+ s_con = nm_setting_connection_new ();
+ nm_connection_add_setting (connection, s_con);
+ }
+ g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, NULL);
+ }
+
+ nm_client_add_and_activate_connection_async (closure->client,
+ connection,
+ device,
+ ap ? nm_object_get_path (NM_OBJECT (ap)) : NULL,
+ NULL,
+ activate_new_cb,
+ NULL);
+ }
+
+ /* Balance nma_wifi_dialog_get_connection() */
+ g_object_unref (connection);
+
+done:
+ gtk_window_destroy (GTK_WINDOW (dialog));
+}
+
+static void
+show_wireless_dialog (GtkWidget *toplevel,
+ NMClient *client,
+ GtkWidget *dialog)
+{
+ WirelessDialogClosure *closure;
+
+ g_debug ("About to parent and show a network dialog");
+
+ g_object_set (G_OBJECT (dialog),
+ "modal", TRUE,
+ "transient-for", toplevel,
+ NULL);
+
+ closure = g_slice_new (WirelessDialogClosure);
+ closure->client = g_object_ref (client);
+ g_signal_connect_data (dialog, "response",
+ G_CALLBACK (wireless_dialog_response_cb),
+ closure, wireless_dialog_closure_closure_notify, 0);
+
+ g_object_bind_property (G_OBJECT (toplevel), "visible",
+ G_OBJECT (dialog), "visible",
+ G_BINDING_SYNC_CREATE);
+}
+
+void
+cc_network_panel_create_wifi_network (GtkWidget *toplevel,
+ NMClient *client)
+{
+ if (wifi_can_create_wifi_network (client)) {
+ show_wireless_dialog (toplevel, client,
+ nma_wifi_dialog_new_for_create (client));
+ }
+}
+
+void
+cc_network_panel_connect_to_hidden_network (GtkWidget *toplevel,
+ NMClient *client)
+{
+ g_debug ("connect to hidden wifi");
+ show_wireless_dialog (toplevel, client,
+ nma_wifi_dialog_new_for_hidden (client));
+}
+
+void
+cc_network_panel_connect_to_8021x_network (GtkWidget *toplevel,
+ NMClient *client,
+ NMDevice *device,
+ const gchar *arg_access_point)
+{
+ NMConnection *connection;
+ NMSettingConnection *s_con;
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+ NMSetting8021x *s_8021x;
+ NM80211ApSecurityFlags wpa_flags, rsn_flags;
+ GtkWidget *dialog;
+ char *uuid;
+ NMAccessPoint *ap;
+
+ g_debug ("connect to 8021x wifi");
+ ap = nm_device_wifi_get_access_point_by_path (NM_DEVICE_WIFI (device), arg_access_point);
+ if (ap == NULL) {
+ g_warning ("didn't find access point with path %s", arg_access_point);
+ return;
+ }
+
+ /* If the AP is WPA[2]-Enterprise then we need to set up a minimal 802.1x
+ * setting and ask the user for more information.
+ */
+ rsn_flags = nm_access_point_get_rsn_flags (ap);
+ wpa_flags = nm_access_point_get_wpa_flags (ap);
+ if (!(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+ && !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
+ g_warning ("Network panel loaded with connect-8021x-wifi but the "
+ "access point does not support 802.1x");
+ return;
+ }
+
+ connection = nm_simple_connection_new ();
+
+ /* Need a UUID for the "always ask" stuff in the Dialog of Doom */
+ s_con = (NMSettingConnection *) nm_setting_connection_new ();
+ uuid = nm_utils_uuid_generate ();
+ g_object_set (s_con, NM_SETTING_CONNECTION_UUID, uuid, NULL);
+ g_free (uuid);
+ nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+ s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+ g_object_set (s_wifi,
+ NM_SETTING_WIRELESS_SSID, nm_access_point_get_ssid (ap),
+ NULL);
+
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+ nm_setting_802_1x_add_eap_method (s_8021x, "ttls");
+ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", NULL);
+ nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+ dialog = nma_wifi_dialog_new (client, connection, device, ap, FALSE);
+ show_wireless_dialog (toplevel, client, dialog);
+}
+
+static void
+connect_3g (NMConnection *connection,
+ gboolean canceled,
+ gpointer user_data)
+{
+ MobileDialogClosure *closure = user_data;
+
+ if (canceled == FALSE) {
+ g_return_if_fail (connection != NULL);
+
+ /* Ask NM to add the new connection and activate it; NM will fill in the
+ * missing details based on the specific object and the device.
+ */
+ nm_client_add_and_activate_connection_async (closure->client,
+ connection,
+ closure->device,
+ "/",
+ NULL,
+ activate_new_cb,
+ NULL);
+ }
+
+ mobile_dialog_closure_free (closure);
+}
+
+static void
+cdma_mobile_wizard_done (NMAMobileWizard *wizard,
+ gboolean canceled,
+ NMAMobileWizardAccessMethod *method,
+ gpointer user_data)
+{
+ NMConnection *connection = NULL;
+
+ if (!canceled && method) {
+ NMSetting *setting;
+ char *uuid, *id;
+
+ if (method->devtype != NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) {
+ g_warning ("Unexpected device type (not CDMA).");
+ canceled = TRUE;
+ goto done;
+ }
+
+ connection = nm_simple_connection_new ();
+
+ setting = nm_setting_cdma_new ();
+ g_object_set (setting,
+ NM_SETTING_CDMA_NUMBER, "#777",
+ NM_SETTING_CDMA_USERNAME, method->username,
+ NM_SETTING_CDMA_PASSWORD, method->password,
+ NULL);
+ nm_connection_add_setting (connection, setting);
+
+ /* Serial setting */
+ setting = nm_setting_serial_new ();
+ g_object_set (setting,
+ NM_SETTING_SERIAL_BAUD, 115200,
+ NM_SETTING_SERIAL_BITS, 8,
+ NM_SETTING_SERIAL_PARITY, 'n',
+ NM_SETTING_SERIAL_STOPBITS, 1,
+ NULL);
+ nm_connection_add_setting (connection, setting);
+
+ nm_connection_add_setting (connection, nm_setting_ppp_new ());
+
+ setting = nm_setting_connection_new ();
+ if (method->plan_name)
+ id = g_strdup_printf ("%s %s", method->provider_name, method->plan_name);
+ else
+ id = g_strdup_printf ("%s connection", method->provider_name);
+ uuid = nm_utils_uuid_generate ();
+ g_object_set (setting,
+ NM_SETTING_CONNECTION_ID, id,
+ NM_SETTING_CONNECTION_TYPE, NM_SETTING_CDMA_SETTING_NAME,
+ NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+ NM_SETTING_CONNECTION_UUID, uuid,
+ NULL);
+ g_free (uuid);
+ g_free (id);
+ nm_connection_add_setting (connection, setting);
+ }
+
+ done:
+ connect_3g (connection, canceled, user_data);
+ nma_mobile_wizard_destroy (wizard);
+}
+
+static void
+gsm_mobile_wizard_done (NMAMobileWizard *wizard,
+ gboolean canceled,
+ NMAMobileWizardAccessMethod *method,
+ gpointer user_data)
+{
+ NMConnection *connection = NULL;
+
+ if (!canceled && method) {
+ NMSetting *setting;
+ char *uuid, *id;
+
+ if (method->devtype != NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) {
+ g_warning ("Unexpected device type (not GSM).");
+ canceled = TRUE;
+ goto done;
+ }
+
+ connection = nm_simple_connection_new ();
+
+ setting = nm_setting_gsm_new ();
+ g_object_set (setting,
+ NM_SETTING_GSM_NUMBER, "*99#",
+ NM_SETTING_GSM_USERNAME, method->username,
+ NM_SETTING_GSM_PASSWORD, method->password,
+ NM_SETTING_GSM_APN, method->gsm_apn,
+ NULL);
+ nm_connection_add_setting (connection, setting);
+
+ /* Serial setting */
+ setting = nm_setting_serial_new ();
+ g_object_set (setting,
+ NM_SETTING_SERIAL_BAUD, 115200,
+ NM_SETTING_SERIAL_BITS, 8,
+ NM_SETTING_SERIAL_PARITY, 'n',
+ NM_SETTING_SERIAL_STOPBITS, 1,
+ NULL);
+ nm_connection_add_setting (connection, setting);
+
+ nm_connection_add_setting (connection, nm_setting_ppp_new ());
+
+ setting = nm_setting_connection_new ();
+ if (method->plan_name)
+ id = g_strdup_printf ("%s %s", method->provider_name, method->plan_name);
+ else
+ id = g_strdup_printf ("%s connection", method->provider_name);
+ uuid = nm_utils_uuid_generate ();
+ g_object_set (setting,
+ NM_SETTING_CONNECTION_ID, id,
+ NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME,
+ NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+ NM_SETTING_CONNECTION_UUID, uuid,
+ NULL);
+ g_free (uuid);
+ g_free (id);
+ nm_connection_add_setting (connection, setting);
+ }
+
+done:
+ connect_3g (connection, canceled, user_data);
+ nma_mobile_wizard_destroy (wizard);
+}
+
+static void
+toplevel_shown (GtkWindow *toplevel,
+ GParamSpec *pspec,
+ NMAMobileWizard *wizard)
+{
+ gboolean visible = FALSE;
+
+ g_object_get (G_OBJECT (toplevel), "visible", &visible, NULL);
+ if (visible)
+ nma_mobile_wizard_present (wizard);
+}
+
+static gboolean
+show_wizard_idle_cb (NMAMobileWizard *wizard)
+{
+ nma_mobile_wizard_present (wizard);
+ return FALSE;
+}
+
+void
+cc_network_panel_connect_to_3g_network (GtkWidget *toplevel,
+ NMClient *client,
+ NMDevice *device)
+{
+ MobileDialogClosure *closure;
+ NMAMobileWizard *wizard;
+ NMDeviceModemCapabilities caps;
+ gboolean visible = FALSE;
+
+ g_debug ("connect to 3g");
+ if (!NM_IS_DEVICE_MODEM (device)) {
+ g_warning ("Network panel loaded with connect-3g but the selected device"
+ " is not a modem");
+ return;
+ }
+
+ closure = g_slice_new (MobileDialogClosure);
+ closure->client = g_object_ref (client);
+ closure->device = g_object_ref (device);
+
+ caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
+ if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) {
+ wizard = nma_mobile_wizard_new (GTK_WINDOW (toplevel), NULL, NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS, FALSE,
+ gsm_mobile_wizard_done, closure);
+ if (wizard == NULL) {
+ g_warning ("failed to construct GSM wizard");
+ return;
+ }
+ } else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) {
+ wizard = nma_mobile_wizard_new (GTK_WINDOW (toplevel), NULL, NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO, FALSE,
+ cdma_mobile_wizard_done, closure);
+ if (wizard == NULL) {
+ g_warning ("failed to construct CDMA wizard");
+ return;
+ }
+ } else {
+ g_warning ("Network panel loaded with connect-3g but the selected device"
+ " does not support GSM or CDMA");
+ mobile_dialog_closure_free (closure);
+ return;
+ }
+
+ g_object_get (G_OBJECT (toplevel), "visible", &visible, NULL);
+ if (visible) {
+ g_debug ("Scheduling showing the Mobile wizard");
+ g_idle_add ((GSourceFunc) show_wizard_idle_cb, wizard);
+ } else {
+ g_debug ("Will show wizard a bit later, toplevel is not visible");
+ g_signal_connect (G_OBJECT (toplevel), "notify::visible",
+ G_CALLBACK (toplevel_shown), wizard);
+ }
+}
diff --git a/gnome-initial-setup/pages/network/network-dialogs.h b/gnome-initial-setup/pages/network/network-dialogs.h
new file mode 100644
index 0000000..0f02a52
--- /dev/null
+++ b/gnome-initial-setup/pages/network/network-dialogs.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _NETWORK_DIALOGS_H
+#define _NETWORK_DIALOGS_H
+
+#include <NetworkManager.h>
+#include <gtk/gtk.h>
+
+void cc_network_panel_create_wifi_network (GtkWidget *toplevel,
+ NMClient *client);
+
+void cc_network_panel_connect_to_hidden_network (GtkWidget *toplevel,
+ NMClient *client);
+
+void cc_network_panel_connect_to_8021x_network (GtkWidget *toplevel,
+ NMClient *client,
+ NMDevice *device,
+ const gchar *arg_access_point);
+
+void cc_network_panel_connect_to_3g_network (GtkWidget *toplevel,
+ NMClient *client,
+ NMDevice *device);
+
+#endif /* _NETWORK_DIALOGS_H */
diff --git a/gnome-initial-setup/pages/network/network.gresource.xml b/gnome-initial-setup/pages/network/network.gresource.xml
new file mode 100644
index 0000000..bf5394f
--- /dev/null
+++ b/gnome-initial-setup/pages/network/network.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/initial-setup">
+ <file preprocess="xml-stripblanks" alias="gis-network-page.ui">gis-network-page.ui</file>
+ </gresource>
+</gresources>