[gnome-initial-setup/82-support-wi-fi-devices-appearing-dynamically: 1/2] network: react to devices being connected



commit cd116759ae82b3442e2d78c459e036081d4ac5e7
Author: Will Thompson <will willthompson co uk>
Date:   Mon Jan 20 09:25:46 2020 +0000

    network: react to devices being connected
    
    If the built-in Wi-Fi device takes longer to initialize than does the
    gnome-initial-setup session, no device will be found when the page is
    first initialized, and the page will not be shown, even if the device
    has come up by the point the user reaches this point in the initial
    setup flow. This has been seen on 2-3 models the Endless hardware
    enablement team has worked with.
    
    To fix this, monitor NetworkManager for new devices, and latch onto the
    first managed Wi-Fi device we ever see.
    
    Previously, the decision about whether to show or hide the page was made
    once, when the page was constructed; with this change, it is now made
    whenever we decide whether the page is complete. To avoid confusing the
    user, if we have ever shown them the page, we continue to show it even
    if the connection comes up – otherwise they cannot go Back and pick a
    different network.
    
    Note that we still do not handle the case of the current Wi-Fi device
    being removed, which may be significant if the device doesn't have a
    built-in Wi-Fi adapter and the user is plugging and unplugging a USB
    one. In particular, unplugging and replugging the same device yields a
    different D-Bus object and NMDevice, so the page will be empty even once
    the device is re-plugged. However, this is not a regression!
    
    We also still don't handle multiple Wi-Fi devices.
    
    https://gitlab.gnome.org/GNOME/gnome-initial-setup/issues/82

 .../pages/network/gis-network-page.c               | 140 +++++++++++++++++----
 1 file changed, 116 insertions(+), 24 deletions(-)
---
diff --git a/gnome-initial-setup/pages/network/gis-network-page.c 
b/gnome-initial-setup/pages/network/gis-network-page.c
index cf0a5dd..8aa844e 100644
--- a/gnome-initial-setup/pages/network/gis-network-page.c
+++ b/gnome-initial-setup/pages/network/gis-network-page.c
@@ -56,6 +56,9 @@ struct _GisNetworkPagePrivate {
   GtkSizeGroup *icons;
 
   guint refresh_timeout_id;
+
+  /* TRUE if the page has ever been shown to the user. */
+  gboolean ever_shown;
 };
 typedef struct _GisNetworkPagePrivate GisNetworkPagePrivate;
 
@@ -604,11 +607,31 @@ 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;
+  }
 
-  activated = (nm_device_get_state (priv->nm_device) == NM_DEVICE_STATE_ACTIVATED);
   gis_page_set_complete (GIS_PAGE (page), activated);
-  schedule_refresh_wireless_list (page);
+  gtk_widget_set_visible (GTK_WIDGET (page), visible);
+
+  if (has_device)
+    schedule_refresh_wireless_list (page);
 }
 
 static void
@@ -626,7 +649,8 @@ find_best_device (GisNetworkPage *page)
 
   /* FIXME: deal with multiple devices and devices being removed */
   if (priv->nm_device != NULL) {
-    g_debug ("Already displaying %s", nm_device_get_description (priv->nm_device));
+    g_debug ("Already showing network device %s",
+             nm_device_get_description (priv->nm_device));
     return;
   }
 
@@ -641,18 +665,91 @@ find_best_device (GisNetworkPage *page)
     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 ("Displaying %s", nm_device_get_description (priv->nm_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);
 
-      sync_complete (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
@@ -660,13 +757,13 @@ gis_network_page_constructed (GObject *object)
 {
   GisNetworkPage *page = GIS_NETWORK_PAGE (object);
   GisNetworkPagePrivate *priv = gis_network_page_get_instance_private (page);
-  gboolean visible = FALSE;
   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);
@@ -680,28 +777,14 @@ gis_network_page_constructed (GObject *object)
     g_warning ("Can't create NetworkManager client, hiding network page: %s",
                error->message);
     g_error_free (error);
-    goto out;
+    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);
-
-  find_best_device (page);
-
-  if (g_getenv ("GIS_ALWAYS_SHOW_NETWORK_PAGE") != NULL) {
-    /* Allow to always show the network page, for debugging purposes */
-    visible = TRUE;
-  } else if (priv->nm_device == NULL) {
-    g_debug ("No network device found, hiding network page");
-  } else if (nm_device_get_state (priv->nm_device) == NM_DEVICE_STATE_ACTIVATED) {
-    g_debug ("Activated network device found, hiding network page");
-  } else {
-    visible = TRUE;
-  }
-
-out:
-  gtk_widget_set_visible (GTK_WIDGET (page), visible);
+  monitor_network_devices (page);
 }
 
 static void
@@ -725,6 +808,14 @@ 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)
 {
@@ -742,6 +833,7 @@ gis_network_page_class_init (GisNetworkPageClass *klass)
 
   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;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]