[network-manager-applet/danw/virtual-devs: 5/5] applet: handle virtual device types better



commit 6c4d9c0fa2028bccb9e1486d4c6ae16f905c0697
Author: Dan Winship <danw gnome org>
Date:   Fri May 17 07:09:43 2013 -0400

    applet: handle virtual device types better
    
    For virtual device types (vlan, bridge, bond), the physical device may
    not be created until the connection is activated. Reorganize things so
    that these device types are represented by their NMConnections, not
    their NMDevices, with the connections grouped together according to
    their virtual interface name.

 src/applet-device-bond.c   |   18 ++--
 src/applet-device-bridge.c |   18 ++--
 src/applet-device-vlan.c   |  148 ++++++++++++++++----
 src/applet.c               |  322 ++++++++++++++++++++++++++++----------------
 4 files changed, 346 insertions(+), 160 deletions(-)
---
diff --git a/src/applet-device-bond.c b/src/applet-device-bond.c
index aa21d5f..ac844b8 100644
--- a/src/applet-device-bond.c
+++ b/src/applet-device-bond.c
@@ -38,6 +38,7 @@
 #include "applet.h"
 #include "applet-device-bond.h"
 #include "utils.h"
+#include "nm-ui-utils.h"
 
 static void
 bond_add_menu_item (NMDevice *device,
@@ -50,7 +51,7 @@ bond_add_menu_item (NMDevice *device,
        char *text;
        GtkWidget *item;
 
-       text = g_strdup_printf (_("Bond (%s)"), nm_device_get_iface (device));
+       text = nma_utils_get_connection_device_name (connections->data);
        item = applet_menu_item_create_device_item_helper (device, applet, text);
        g_free (text);
 
@@ -62,20 +63,20 @@ bond_add_menu_item (NMDevice *device,
                applet_add_connection_items (device, connections, TRUE, active, NMA_ADD_ACTIVE, menu, applet);
 
        /* Notify user of unmanaged or unavailable device */
-       item = nma_menu_device_get_menu_item (device, applet, NULL);
-       if (item) {
-               gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-               gtk_widget_show (item);
+       if (device) {
+               item = nma_menu_device_get_menu_item (device, applet, NULL);
+               if (item) {
+                       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+                       gtk_widget_show (item);
+               }
        }
 
-       if (!nma_menu_device_check_unusable (device)) {
+       if (!device || !nma_menu_device_check_unusable (device)) {
                if ((!active && g_slist_length (connections)) || (active && g_slist_length (connections) > 1))
                        applet_menu_item_add_complex_separator_helper (menu, applet, _("Available"), -1);
 
                if (g_slist_length (connections))
                        applet_add_connection_items (device, connections, TRUE, active, NMA_ADD_INACTIVE, 
menu, applet);
-               else
-                       applet_add_default_connection_item (device, _("Configure bond connections..."), TRUE, 
menu, applet);
        }
 }
 
@@ -138,7 +139,6 @@ bond_new_auto_connection (NMDevice *device,
                           AppletNewAutoConnectionCallback callback,
                           gpointer callback_data)
 {
-       nma_edit_connections ();
        return FALSE;
 }
 
diff --git a/src/applet-device-bridge.c b/src/applet-device-bridge.c
index c6e0e39..008a794 100644
--- a/src/applet-device-bridge.c
+++ b/src/applet-device-bridge.c
@@ -38,6 +38,7 @@
 #include "applet.h"
 #include "applet-device-bridge.h"
 #include "utils.h"
+#include "nm-ui-utils.h"
 
 static void
 bridge_add_menu_item (NMDevice *device,
@@ -50,7 +51,7 @@ bridge_add_menu_item (NMDevice *device,
        char *text;
        GtkWidget *item;
 
-       text = g_strdup_printf (_("Bridge (%s)"), nm_device_get_iface (device));
+       text = nma_utils_get_connection_device_name (connections->data);
        item = applet_menu_item_create_device_item_helper (device, applet, text);
        g_free (text);
 
@@ -62,20 +63,20 @@ bridge_add_menu_item (NMDevice *device,
                applet_add_connection_items (device, connections, TRUE, active, NMA_ADD_ACTIVE, menu, applet);
 
        /* Notify user of unmanaged or unavailable device */
-       item = nma_menu_device_get_menu_item (device, applet, NULL);
-       if (item) {
-               gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-               gtk_widget_show (item);
+       if (device) {
+               item = nma_menu_device_get_menu_item (device, applet, NULL);
+               if (item) {
+                       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+                       gtk_widget_show (item);
+               }
        }
 
-       if (!nma_menu_device_check_unusable (device)) {
+       if (!device || !nma_menu_device_check_unusable (device)) {
                if ((!active && g_slist_length (connections)) || (active && g_slist_length (connections) > 1))
                        applet_menu_item_add_complex_separator_helper (menu, applet, _("Available"), -1);
 
                if (g_slist_length (connections))
                        applet_add_connection_items (device, connections, TRUE, active, NMA_ADD_INACTIVE, 
menu, applet);
-               else
-                       applet_add_default_connection_item (device, _("Configure bridge connections..."), 
TRUE, menu, applet);
        }
 }
 
@@ -138,7 +139,6 @@ bridge_new_auto_connection (NMDevice *device,
                             AppletNewAutoConnectionCallback callback,
                             gpointer callback_data)
 {
-       nma_edit_connections ();
        return FALSE;
 }
 
diff --git a/src/applet-device-vlan.c b/src/applet-device-vlan.c
index 582251b..2f6aa3d 100644
--- a/src/applet-device-vlan.c
+++ b/src/applet-device-vlan.c
@@ -32,6 +32,7 @@
 #include <nm-setting-connection.h>
 #include <nm-setting-wired.h>
 #include <nm-setting-vlan.h>
+#include <nm-device-ethernet.h>
 #include <nm-device-vlan.h>
 #include <nm-utils.h>
 
@@ -39,6 +40,106 @@
 #include "applet-device-vlan.h"
 #include "nm-ui-utils.h"
 
+static NMDevice *
+find_device_by_iface (const char *iface, const GPtrArray *devices)
+{
+       NMDevice *candidate;
+       int i;
+
+       for (i = 0; i < devices->len; i++) {
+               candidate = devices->pdata[i];
+
+               if (!g_strcmp0 (iface, nm_device_get_iface (candidate)))
+                       return candidate;
+       }
+       return NULL;
+}
+
+static NMDevice *
+find_device_by_mac (const GByteArray *mac, const GPtrArray *devices)
+{
+       NMDevice *candidate, *device = NULL;
+       char *vlan_hw_address, *candidate_hw_address;
+       int i;
+
+       vlan_hw_address = nm_utils_hwaddr_ntoa (mac->data, nm_utils_hwaddr_type (mac->len));
+
+       for (i = 0; i < devices->len && device == NULL; i++) {
+               candidate = devices->pdata[i];
+
+               if (!g_object_class_find_property (G_OBJECT_GET_CLASS (candidate),
+                                                  "hw-address"))
+                       continue;
+
+               g_object_get (G_OBJECT (candidate),
+                             "hw-address", &candidate_hw_address,
+                             NULL);
+               if (!g_strcmp0 (vlan_hw_address, candidate_hw_address))
+                       device = candidate;
+               g_free (candidate_hw_address);
+       }
+       g_free (vlan_hw_address);
+
+       return device;
+}
+
+static NMDevice *
+find_vlan_parent (GSList *connections, NMApplet *applet)
+{
+       const GPtrArray *devices;
+       NMDevice *parent_device;
+       GSList *iter;
+
+       devices = nm_client_get_devices (applet->nm_client);
+       if (!devices)
+               return NULL;
+
+       for (iter = connections; iter; iter = iter->next) {
+               NMConnection *connection = iter->data;
+               NMSettingVlan *s_vlan;
+               const char *parent;
+
+               s_vlan = nm_connection_get_setting_vlan (connection);
+               g_return_val_if_fail (s_vlan != NULL, NULL);
+
+               parent = nm_setting_vlan_get_parent (s_vlan);
+               if (parent && nm_utils_iface_valid_name (parent)) {
+                       parent_device = find_device_by_iface (parent, devices);
+               } else {
+                       NMSettingConnection *s_con;
+                       NMSetting *s_hw;
+                       const char *type;
+                       GByteArray *mac;
+
+                       s_con = nm_connection_get_setting_connection (connection);
+                       type = nm_setting_connection_get_connection_type (s_con);
+                       s_hw = nm_connection_get_setting_by_name (connection, type);
+                       if (!s_hw) {
+                               g_warn_if_reached ();
+                               continue;
+                       }
+
+                       if (!g_object_class_find_property (G_OBJECT_GET_CLASS (s_hw),
+                                                          "mac-address"))
+                               continue;
+
+                       g_object_get (G_OBJECT (s_hw),
+                                     "mac-address", &mac,
+                                     NULL);
+                       if (mac) {
+                               parent_device = find_device_by_mac (mac, devices);
+                               g_byte_array_unref (mac);
+                       } else
+                               parent_device = NULL;
+               }
+               
+               if (parent_device)
+                       return parent_device;
+       }
+
+       return NULL;
+}
+
 static void
 vlan_add_menu_item (NMDevice *device,
                     gboolean multiple_devices,
@@ -51,30 +152,22 @@ vlan_add_menu_item (NMDevice *device,
        GtkWidget *item;
        gboolean carrier = TRUE;
 
-       if (multiple_devices) {
-               const char *desc;
-
-               desc = nma_utils_get_device_description (device);
-
-               if (g_slist_length (connections) > 1)
-                       text = g_strdup_printf (_("VLANs (%s)"), desc);
-               else
-                       text = g_strdup_printf (_("VLAN (%s)"), desc);
-       } else {
-               if (g_slist_length (connections) > 1)
-                       text = g_strdup (_("VLANs"));
-               else
-                       text = g_strdup (_("VLAN"));
-       }
-
+       text = nma_utils_get_connection_device_name (connections->data);
        item = applet_menu_item_create_device_item_helper (device, applet, text);
        g_free (text);
 
-       /* Only dim the item if the device supports carrier detection AND
-        * we know it doesn't have a link.
-        */
-       if (nm_device_get_capabilities (device) & NM_DEVICE_CAP_CARRIER_DETECT)
+       /* If the VLAN device exists, check its carrier */
+       if (device && nm_device_get_capabilities (device) & NM_DEVICE_CAP_CARRIER_DETECT)
                carrier = nm_device_vlan_get_carrier (NM_DEVICE_VLAN (device));
+       else {
+               NMDevice *parent;
+
+               /* If we can find its parent, check the parent's carrier */
+               parent = find_vlan_parent (connections, applet);
+
+               if (parent && nm_device_get_capabilities (parent) & NM_DEVICE_CAP_CARRIER_DETECT)
+                       g_object_get (G_OBJECT (parent), "carrier", &carrier, NULL);
+       } /* else fall back to assuming carrier is present */           
 
        gtk_widget_set_sensitive (item, FALSE);
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
@@ -84,20 +177,20 @@ vlan_add_menu_item (NMDevice *device,
                applet_add_connection_items (device, connections, carrier, active, NMA_ADD_ACTIVE, menu, 
applet);
 
        /* Notify user of unmanaged or unavailable device */
-       item = nma_menu_device_get_menu_item (device, applet, carrier ? NULL : _("disconnected"));
-       if (item) {
-               gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-               gtk_widget_show (item);
+       if (device) {
+               item = nma_menu_device_get_menu_item (device, applet, carrier ? NULL : _("disconnected"));
+               if (item) {
+                       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+                       gtk_widget_show (item);
+               }
        }
 
-       if (!nma_menu_device_check_unusable (device)) {
+       if (!device || !nma_menu_device_check_unusable (device)) {
                if ((!active && g_slist_length (connections)) || (active && g_slist_length (connections) > 1))
                        applet_menu_item_add_complex_separator_helper (menu, applet, _("Available"), -1);
 
                if (g_slist_length (connections))
                        applet_add_connection_items (device, connections, carrier, active, NMA_ADD_INACTIVE, 
menu, applet);
-               else
-                       applet_add_default_connection_item (device, _("Configure VLAN connections..."), 
carrier, menu, applet);
        }
 }
 
@@ -160,7 +253,6 @@ vlan_new_auto_connection (NMDevice *device,
                           AppletNewAutoConnectionCallback callback,
                           gpointer callback_data)
 {
-       nma_edit_connections ();
        return FALSE;
 }
 
diff --git a/src/applet.c b/src/applet.c
index 86db87b..21376aa 100644
--- a/src/applet.c
+++ b/src/applet.c
@@ -305,6 +305,12 @@ get_device_class_from_connection (NMConnection *connection, NMApplet *applet)
                return applet->cdma_class;
        else if (!strcmp (ctype, NM_SETTING_BLUETOOTH_SETTING_NAME))
                return applet->bt_class;
+       else if (!strcmp (ctype, NM_SETTING_BOND_SETTING_NAME))
+               return applet->bond_class;
+       else if (!strcmp (ctype, NM_SETTING_BRIDGE_SETTING_NAME))
+               return applet->bridge_class;
+       else if (!strcmp (ctype, NM_SETTING_VLAN_SETTING_NAME))
+               return applet->vlan_class;
        else
                g_warning ("%s: unhandled connection type '%s'", __func__, ctype);
        return NULL;
@@ -643,8 +649,6 @@ applet_menu_item_activate_helper (NMDevice *device,
        AppletItemActivateInfo *info;
        NMADeviceClass *dclass;
 
-       g_return_if_fail (NM_IS_DEVICE (device));
-
        if (connection) {
                /* If the menu item had an associated connection already, just tell
                 * NM to activate that connection.
@@ -658,6 +662,8 @@ applet_menu_item_activate_helper (NMDevice *device,
                return;
        }
 
+       g_return_if_fail (NM_IS_DEVICE (device));
+
        /* If no connection was given, ask the device class to create a new
         * default connection for this device type.  This could be a wizard,
         * and thus take a while.
@@ -1350,57 +1356,18 @@ static void nma_menu_add_text_item (GtkWidget *menu, char *text)
        gtk_widget_show (menu_item);
 }
 
-static guint
-get_device_order (GType dtype)
-{
-       static GType order[30] = { G_TYPE_INVALID };
-       guint i = 0;
-
-       if (G_UNLIKELY (order[0] == G_TYPE_INVALID)) {
-               order[i++] = NM_TYPE_DEVICE_BRIDGE;
-               order[i++] = NM_TYPE_DEVICE_BOND;
-               order[i++] = NM_TYPE_DEVICE_ETHERNET;
-               order[i++] = NM_TYPE_DEVICE_INFINIBAND;
-               order[i++] = NM_TYPE_DEVICE_VLAN;
-               order[i++] = NM_TYPE_DEVICE_WIFI;
-               order[i++] = NM_TYPE_DEVICE_MODEM;
-               order[i++] = NM_TYPE_DEVICE_BT;
-               /* LAST */
-               order[i++] = G_TYPE_INVALID;
-       }
-
-       for (i = 0; i < G_N_ELEMENTS (order) && order[i] != G_TYPE_INVALID; i++) {
-               if (order[i] == dtype)
-                       break;
-       }
-
-       return i;
-}
-
 static gint
-sort_devices (gconstpointer a, gconstpointer b)
+sort_devices_by_description (gconstpointer a, gconstpointer b)
 {
        NMDevice *aa = NM_DEVICE (a);
        NMDevice *bb = NM_DEVICE (b);
-       guint aa_order, bb_order;
-
-       aa_order = get_device_order (G_OBJECT_TYPE (aa));
-       bb_order = get_device_order (G_OBJECT_TYPE (bb));
+       const char *aa_desc;
+       const char *bb_desc;
 
-       if (aa_order == bb_order) {
-               const char *aa_desc = NULL;
-               const char *bb_desc = NULL;
+       aa_desc = nma_utils_get_device_description (aa);
+       bb_desc = nma_utils_get_device_description (bb);
 
-               aa_desc = nma_utils_get_device_description (aa);
-               bb_desc = nma_utils_get_device_description (bb);
-
-               return g_strcmp0 (aa_desc, bb_desc);
-       }
-
-       if (aa_order < bb_order)
-               return -1;
-
-       return 1;
+       return g_strcmp0 (aa_desc, bb_desc);
 }
 
 static gboolean
@@ -1458,6 +1425,47 @@ applet_find_active_connection_for_device (NMDevice *device,
        return connection;
 }
 
+static NMConnection *
+applet_find_active_connection_for_virtual_device (const char *iface,
+                                                  NMApplet *applet,
+                                                  NMActiveConnection **out_active)
+{
+       const GPtrArray *active_connections;
+       NMConnection *connection = NULL;
+       int i;
+
+       g_return_val_if_fail (iface != NULL, NULL);
+       g_return_val_if_fail (NM_IS_APPLET (applet), NULL);
+       if (out_active)
+               g_return_val_if_fail (*out_active == NULL, NULL);
+
+       active_connections = nm_client_get_active_connections (applet->nm_client);
+       for (i = 0; active_connections && (i < active_connections->len); i++) {
+               NMRemoteConnection *tmp;
+               NMActiveConnection *active;
+               const char *connection_path;
+
+               active = NM_ACTIVE_CONNECTION (g_ptr_array_index (active_connections, i));
+               connection_path = nm_active_connection_get_connection (active);
+
+               if (!connection_path)
+                       continue;
+
+               tmp = nm_remote_settings_get_connection_by_path (applet->settings, connection_path);
+               if (!tmp)
+                       continue;
+
+               if (!g_strcmp0 (nm_connection_get_virtual_iface_name (NM_CONNECTION (tmp)), iface)) {
+                       connection = NM_CONNECTION (tmp);
+                       if (out_active)
+                               *out_active = active;
+                       break;
+               }
+       }
+
+       return connection;
+}
+
 gboolean
 nma_menu_device_check_unusable (NMDevice *device)
 {
@@ -1557,89 +1565,154 @@ nma_menu_device_get_menu_item (NMDevice *device,
        return item;
 }
 
-static guint32
-nma_menu_add_devices (GtkWidget *menu, NMApplet *applet)
+static int
+add_device_items (NMDeviceType type, const GPtrArray *all_devices, GSList *all_connections,
+                  GtkWidget *menu, NMApplet *applet)
 {
-       const GPtrArray *temp = NULL;
-       GSList *devices = NULL, *iter = NULL;
-       gint n_wifi_devices = 0;
-       gint n_usable_wifi_devices = 0;
-       gint n_ethernet_devices = 0;
-       gint n_mb_devices = 0;
-       gint n_bt_devices = 0;
-       int i;
+       GSList *devices = NULL, *iter;
+       int i, n_devices = 0;
+
+       for (i = 0; all_devices && (i < all_devices->len); i++) {
+               NMDevice *device = all_devices->pdata[i];
 
-       temp = nm_client_get_devices (applet->nm_client);
-       for (i = 0; temp && (i < temp->len); i++)
-               devices = g_slist_insert_sorted (devices, g_ptr_array_index (temp, i), sort_devices);
+               if (nm_device_get_device_type (device) == type) {
+                       n_devices++;
+                       devices = g_slist_prepend (devices, device);
+               }
+       }
+       devices = g_slist_sort (devices, sort_devices_by_description);
 
        for (iter = devices; iter; iter = iter->next) {
-               NMDevice *device = NM_DEVICE (iter->data);
+               NMDevice *device = iter->data;
+               NMADeviceClass *dclass;
+               NMConnection *active;
+               GSList *connections;
+
+               dclass = get_device_class (device, applet);
+               g_assert (dclass != NULL);
+
+               connections = nm_device_filter_connections (device, all_connections);
+               active = applet_find_active_connection_for_device (device, applet, NULL);
 
-               /* Ignore unsupported devices */
-               if (!(nm_device_get_capabilities (device) & NM_DEVICE_CAP_NM_SUPPORTED))
+               dclass->add_menu_item (device, n_devices > 1, connections, active, menu, applet);
+
+               g_slist_free (connections);
+       }
+
+       g_slist_free (devices);
+       return n_devices;
+}
+
+static gint
+sort_devices_by_interface (gconstpointer a, gconstpointer b)
+{
+       NMConnection *aa = NM_CONNECTION (a);
+       NMConnection *bb = NM_CONNECTION (b);
+
+       return strcmp (nm_connection_get_virtual_iface_name (aa),
+                      nm_connection_get_virtual_iface_name (bb));
+}
+
+static int
+add_virtual_items (const char *type, const GPtrArray *all_devices,
+                   GSList *all_connections, GtkWidget *menu, NMApplet *applet)
+{
+       GSList *iter, *connections = NULL;
+       int n_devices = 0;
+
+       for (iter = all_connections; iter; iter = iter->next) {
+               NMConnection *connection = iter->data;
+
+               if (!nm_connection_get_virtual_iface_name (connection))
                        continue;
 
-               if (NM_IS_DEVICE_WIFI (device)) {
-                       n_wifi_devices++;
-                       if (   nm_client_wireless_get_enabled (applet->nm_client)
-                           && (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED))
-                               n_usable_wifi_devices++;
-               } else if (NM_IS_DEVICE_ETHERNET (device))
-                       n_ethernet_devices++;
-               else if (NM_IS_DEVICE_MODEM (device))
-                       n_mb_devices++;
-               else if (NM_IS_DEVICE_BT (device))
-                       n_bt_devices++;
+               if (nm_connection_is_type (connection, type))
+                       connections = g_slist_prepend (connections, connection);
        }
 
-       if (!n_ethernet_devices && !n_wifi_devices && !n_mb_devices && !n_bt_devices) {
-               nma_menu_add_text_item (menu, _("No network devices available"));
-               goto out;
+       if (!connections)
+               return 0;
+
+       connections = g_slist_sort (connections, sort_devices_by_interface);
+       /* Count the number of unique interface names */
+       iter = connections;
+       while (iter) {
+               NMConnection *connection = iter->data;
+
+               n_devices++;
+               while (iter && sort_devices_by_interface (connection, iter->data) == 0)
+                       iter = iter->next;
        }
 
-       /* Add all devices in our device list to the menu */
-       for (iter = devices; iter; iter = iter->next) {
-               NMDevice *device = NM_DEVICE (iter->data);
-               gint n_devices;
+
+       iter = connections;
+       while (iter) {
+               NMConnection *connection = iter->data;
+               NMDevice *device = NULL;
+               const char *iface = nm_connection_get_virtual_iface_name (connection);
+               GSList *iface_connections = NULL;
                NMADeviceClass *dclass;
                NMConnection *active;
-               GSList *all, *connections;
+               int i;
 
-               /* Ignore unsupported devices */
-               if (!(nm_device_get_capabilities (device) & NM_DEVICE_CAP_NM_SUPPORTED))
-                       continue;
-               dclass = get_device_class (device, applet);
-               if (!dclass)
-                       continue;
+               for (i = 0; all_devices && (i < all_devices->len); i++) {
+                       NMDevice *candidate = all_devices->pdata[i];
 
-               if (NM_IS_DEVICE_WIFI (device))
-                       n_devices = n_wifi_devices;
-               else if (NM_IS_DEVICE_ETHERNET (device))
-                       n_devices = n_ethernet_devices;
-               else if (NM_IS_DEVICE_MODEM (device))
-                       n_devices = n_mb_devices;
-               else
-                       n_devices = 0;
+                       if (!strcmp (nm_device_get_iface (candidate), iface)) {
+                               device = candidate;
+                               break;
+                       }
+               }
 
-               all = applet_get_all_connections (applet);
-               connections = nm_device_filter_connections (device, all);
-               g_slist_free (all);
+               while (iter && sort_devices_by_interface (connection, iter->data) == 0) {
+                       iface_connections = g_slist_prepend (iface_connections, connection);
+                       iter = iter->next;
+               }
 
-               active = applet_find_active_connection_for_device (device, applet, NULL);
+               active = applet_find_active_connection_for_virtual_device (iface, applet, NULL);
 
-               dclass->add_menu_item (device, n_devices > 1, connections, active, menu, applet);
+               dclass = get_device_class_from_connection (connection, applet);
+               dclass->add_menu_item (device, n_devices > 1, iface_connections, active, menu, applet);
 
-               g_slist_free (connections);
+               g_slist_free (iface_connections);
        }
 
- out:
-       g_slist_free (devices);
+       g_slist_free (connections);
+       return n_devices;
+}
 
-       /* Return # of usable wifi devices here for correct enable/disable state
-        * of things like Enable Wi-Fi, "Connect to other..." and such.
-        */
-       return n_usable_wifi_devices;
+static void
+nma_menu_add_devices (GtkWidget *menu, NMApplet *applet)
+{
+       const GPtrArray *all_devices;
+       GSList *all_connections;
+       gint n_items;
+
+       all_connections = applet_get_all_connections (applet);
+       all_devices = nm_client_get_devices (applet->nm_client);
+
+       n_items = 0;
+       n_items += add_virtual_items (NM_SETTING_BRIDGE_SETTING_NAME,
+                                     all_devices, all_connections, menu, applet);
+       n_items += add_virtual_items (NM_SETTING_BOND_SETTING_NAME,
+                                     all_devices, all_connections, menu, applet);
+       n_items += add_device_items  (NM_DEVICE_TYPE_ETHERNET,
+                                     all_devices, all_connections, menu, applet);
+       n_items += add_device_items  (NM_DEVICE_TYPE_INFINIBAND,
+                                     all_devices, all_connections, menu, applet);
+       n_items += add_virtual_items (NM_SETTING_VLAN_SETTING_NAME,
+                                     all_devices, all_connections, menu, applet);
+       n_items += add_device_items  (NM_DEVICE_TYPE_WIFI,
+                                     all_devices, all_connections, menu, applet);
+       n_items += add_device_items  (NM_DEVICE_TYPE_MODEM,
+                                     all_devices, all_connections, menu, applet);
+       n_items += add_device_items  (NM_DEVICE_TYPE_BT,
+                                     all_devices, all_connections, menu, applet);
+
+       g_slist_free (all_connections);
+
+       if (!n_items)
+               nma_menu_add_text_item (menu, _("No network devices available"));
 }
 
 static int
@@ -1831,6 +1904,30 @@ nma_set_notifications_enabled_cb (GtkWidget *widget, NMApplet *applet)
                                !state);
 }
 
+static gboolean
+has_usable_wifi (NMApplet *applet)
+{
+       const GPtrArray *devices;
+       int i;
+
+       if (!nm_client_wireless_get_enabled (applet->nm_client))
+               return FALSE;
+
+       devices = nm_client_get_devices (applet->nm_client);
+       if (!devices)
+               return FALSE;
+
+       for (i = 0; i < devices->len; i++) {
+               NMDevice *device = devices->pdata[i];
+
+               if (   NM_IS_DEVICE_WIFI (device)
+                   && (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 /*
  * nma_menu_show_cb
  *
@@ -1839,8 +1936,6 @@ nma_set_notifications_enabled_cb (GtkWidget *widget, NMApplet *applet)
  */
 static void nma_menu_show_cb (GtkWidget *menu, NMApplet *applet)
 {
-       guint32 n_wifi;
-
        g_return_if_fail (menu != NULL);
        g_return_if_fail (applet != NULL);
 
@@ -1856,11 +1951,10 @@ static void nma_menu_show_cb (GtkWidget *menu, NMApplet *applet)
                return;
        }
 
-       n_wifi = nma_menu_add_devices (menu, applet);
-
+       nma_menu_add_devices (menu, applet);
        nma_menu_add_vpn_submenu (menu, applet);
 
-       if (n_wifi > 0 && nm_client_wireless_get_enabled (applet->nm_client)) {
+       if (has_usable_wifi (applet)) {
                /* Add the "Hidden Wi-Fi network..." entry */
                nma_menu_add_separator_item (menu);
                nma_menu_add_hidden_network_item (menu, applet);
@@ -2224,7 +2318,7 @@ applet_add_connection_items (NMDevice *device,
 
                info = g_slice_new0 (AppletMenuItemInfo);
                info->applet = applet;
-               info->device = g_object_ref (device);
+               info->device = device ? g_object_ref (device) : NULL;
                info->connection = g_object_ref (connection);
 
                g_signal_connect_data (item, "activate",


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