libnm/libnm-glib: add NMClient.get_all_devices() method and AllDevices property
authorDan Williams <dcbw@redhat.com>
Fri, 10 Oct 2014 19:28:49 +0000 (14:28 -0500)
committerThomas Haller <thaller@redhat.com>
Fri, 4 Dec 2015 11:16:41 +0000 (12:16 +0100)
Mirror new NetworkManager API to return both real devices and
device placeholders.

examples/python/gi/get-devices.py [new file with mode: 0755]
libnm-glib/libnm-glib.ver
libnm-glib/nm-client.c
libnm-glib/nm-client.h
libnm-glib/tests/test-nm-client.c
libnm/libnm.ver
libnm/nm-client.c
libnm/nm-client.h
libnm/nm-manager.c
libnm/nm-manager.h
tools/test-networkmanager-service.py

diff --git a/examples/python/gi/get-devices.py b/examples/python/gi/get-devices.py
new file mode 100755 (executable)
index 0000000..5a387bd
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# vim: ft=python ts=4 sts=4 sw=4 et ai
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# 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.
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+
+# This example lists all devices, both real and placeholder ones
+
+from gi.repository import GLib, NM
+
+if __name__ == "__main__":
+    client = NM.Client.new(None)
+    devices = client.get_all_devices()
+
+    print "Real devices"
+    print "------------"
+    for d in devices:
+        if d.is_real():
+            print "%s (%s): %s" % (d.get_iface(), d.get_type_description(), d.get_state())
+
+    print "\nUnrealized/placeholder devices"
+    print "------------------------------"
+    for d in devices:
+        if not d.is_real():
+            print "%s (%s): %s" % (d.get_iface(), d.get_type_description(), d.get_state())
+
index 5335258..bce31b0 100644 (file)
@@ -47,6 +47,7 @@ global:
        nm_client_error_quark;
        nm_client_get_activating_connection;
        nm_client_get_active_connections;
+       nm_client_get_all_devices;
        nm_client_get_connectivity;
        nm_client_get_device_by_iface;
        nm_client_get_device_by_path;
index a30b096..248b9d9 100644 (file)
@@ -59,6 +59,7 @@ typedef struct {
        NMState state;
        gboolean startup;
        GPtrArray *devices;
+       GPtrArray *all_devices;
        GPtrArray *active_connections;
        NMConnectivityState connectivity;
        NMActiveConnection *primary_connection;
@@ -101,6 +102,7 @@ enum {
        PROP_PRIMARY_CONNECTION,
        PROP_ACTIVATING_CONNECTION,
        PROP_DEVICES,
+       PROP_ALL_DEVICES,
 
        LAST_PROP
 };
@@ -108,6 +110,8 @@ enum {
 enum {
        DEVICE_ADDED,
        DEVICE_REMOVED,
+       ANY_DEVICE_ADDED,
+       ANY_DEVICE_REMOVED,
        PERMISSION_CHANGED,
 
        LAST_SIGNAL
@@ -160,8 +164,8 @@ poke_wireless_devices_with_rf_status (NMClient *client)
        NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
        int i;
 
-       for (i = 0; priv->devices && (i < priv->devices->len); i++) {
-               NMDevice *device = g_ptr_array_index (priv->devices, i);
+       for (i = 0; priv->all_devices && (i < priv->all_devices->len); i++) {
+               NMDevice *device = g_ptr_array_index (priv->all_devices, i);
 
                if (NM_IS_DEVICE_WIFI (device))
                        _nm_device_wifi_set_wireless_enabled (NM_DEVICE_WIFI (device), priv->wireless_enabled);
@@ -194,6 +198,7 @@ register_properties (NMClient *client)
                { NM_CLIENT_PRIMARY_CONNECTION,        &priv->primary_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
                { NM_CLIENT_ACTIVATING_CONNECTION,     &priv->activating_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
                { NM_CLIENT_DEVICES,                   &priv->devices, NULL, NM_TYPE_DEVICE, "device" },
+               { NM_CLIENT_ALL_DEVICES,               &priv->all_devices, NULL, NM_TYPE_DEVICE, "any-device" },
                { NULL },
        };
 
@@ -378,6 +383,34 @@ nm_client_get_devices (NMClient *client)
        return handle_ptr_array_return (NM_CLIENT_GET_PRIVATE (client)->devices);
 }
 
+/**
+ * nm_client_get_all_devices:
+ * @client: a #NMClient
+ *
+ * Gets both real devices and device placeholders (eg, software devices which
+ * do not currently exist, but could be created automatically by NetworkManager
+ * if one of their NMDevice::ActivatableConnections was activated).  Use
+ * nm_device_is_real() to determine whether each device is a real device or
+ * a placeholder.
+ *
+ * Use nm_device_get_type() or the NM_IS_DEVICE_XXXX() functions to determine
+ * what kind of device each member of the returned array is, and then you may
+ * use device-specific methods such as nm_device_ethernet_get_hw_address().
+ *
+ * Returns: (transfer none) (element-type NMDevice): a #GPtrArray
+ * containing all the #NMDevices.  The returned array is owned by the
+ * #NMClient object and should not be modified.
+ *
+ * Since: 1.2
+ **/
+const GPtrArray *
+nm_client_get_all_devices (NMClient *client)
+{
+       g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+       return NM_CLIENT_GET_PRIVATE (client)->all_devices;
+}
+
 /**
  * nm_client_get_device_by_path:
  * @client: a #NMClient
@@ -1291,25 +1324,55 @@ nm_client_get_activating_connection (NMClient *client)
 /****************************************************************/
 
 static void
-free_devices (NMClient *client, gboolean emit_signals)
+free_devices (NMClient *client, gboolean in_dispose)
 {
        NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-       GPtrArray *devices;
-       NMDevice *device;
-       int i;
+       gs_unref_ptrarray GPtrArray *real_devices = NULL;
+       gs_unref_ptrarray GPtrArray *all_devices = NULL;
+       GPtrArray *devices = NULL;
+       guint i, j;
 
-       if (!priv->devices)
-               return;
+       real_devices = priv->devices;
+       all_devices = priv->all_devices;
 
-       devices = priv->devices;
-       priv->devices = NULL;
-       for (i = 0; i < devices->len; i++) {
-               device = devices->pdata[i];
-               if (emit_signals)
-                       g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
-               g_object_unref (device);
+       if (in_dispose) {
+               priv->devices = NULL;
+               priv->all_devices = NULL;
+       } else {
+               priv->devices = g_ptr_array_new ();
+               priv->all_devices = g_ptr_array_new ();
+       }
+
+       if (all_devices && all_devices->len > 0)
+               devices = all_devices;
+       else if (devices && devices->len > 0)
+               devices = real_devices;
+
+       if (real_devices && devices != real_devices) {
+               for (i = 0; i < real_devices->len; i++) {
+                       NMDevice *d = real_devices->pdata[i];
+
+                       if (all_devices) {
+                               for (j = 0; j < all_devices->len; j++) {
+                                       if (d == all_devices->pdata[j])
+                                               goto next;
+                               }
+                       }
+                       if (!in_dispose)
+                               g_signal_emit (client, signals[DEVICE_REMOVED], 0, d);
+next:
+                       g_object_unref (d);
+               }
+       }
+       if (devices) {
+               for (i = 0; i < devices->len; i++) {
+                       NMDevice *d = devices->pdata[i];
+
+                       if (!in_dispose)
+                               g_signal_emit (client, signals[DEVICE_REMOVED], 0, d);
+                       g_object_unref (d);
+               }
        }
-       g_ptr_array_free (devices, TRUE);
 }
 
 static void
@@ -1382,7 +1445,7 @@ proxy_name_owner_changed (DBusGProxy *proxy,
                _nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
                _nm_object_suppress_property_updates (NM_OBJECT (client), TRUE);
                poke_wireless_devices_with_rf_status (client);
-               free_devices (client, TRUE);
+               free_devices (client, FALSE);
                free_active_connections (client, TRUE);
                update_permissions (client, NULL);
                priv->wireless_enabled = FALSE;
@@ -1980,7 +2043,7 @@ dispose (GObject *object)
        g_clear_object (&priv->client_proxy);
        g_clear_object (&priv->bus_proxy);
 
-       free_devices (client, FALSE);
+       free_devices (client, TRUE);
        free_active_connections (client, FALSE);
        g_clear_object (&priv->primary_connection);
        g_clear_object (&priv->activating_connection);
@@ -2106,6 +2169,9 @@ get_property (GObject *object,
        case PROP_DEVICES:
                g_value_set_boxed (value, nm_client_get_devices (self));
                break;
+       case PROP_ALL_DEVICES:
+               g_value_set_boxed (value, nm_client_get_all_devices (self));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -2323,7 +2389,7 @@ nm_client_class_init (NMClientClass *client_class)
        /**
         * NMClient:devices:
         *
-        * List of known network devices.
+        * List of real network devices.  Does not include placeholder devices.
         *
         * Since: 0.9.10
         **/
@@ -2334,6 +2400,20 @@ nm_client_class_init (NMClientClass *client_class)
                                     G_PARAM_READABLE |
                                     G_PARAM_STATIC_STRINGS));
 
+       /**
+        * NMClient:all-devices:
+        *
+        * List of both real devices and device placeholders.
+        *
+        * Since: 1.2
+        **/
+       g_object_class_install_property
+               (object_class, PROP_ALL_DEVICES,
+                g_param_spec_boxed (NM_CLIENT_ALL_DEVICES, "", "",
+                                    NM_TYPE_OBJECT_ARRAY,
+                                    G_PARAM_READABLE |
+                                    G_PARAM_STATIC_STRINGS));
+
        /* signals */
 
        /**
@@ -2341,7 +2421,8 @@ nm_client_class_init (NMClientClass *client_class)
         * @client: the client that received the signal
         * @device: (type NMDevice): the new device
         *
-        * Notifies that a #NMDevice is added.
+        * Notifies that a #NMDevice is added.  This signal is not emitted for
+        * placeholder devices.
         **/
        signals[DEVICE_ADDED] =
                g_signal_new ("device-added",
@@ -2357,7 +2438,8 @@ nm_client_class_init (NMClientClass *client_class)
         * @client: the client that received the signal
         * @device: (type NMDevice): the removed device
         *
-        * Notifies that a #NMDevice is removed.
+        * Notifies that a #NMDevice is removed.  This signal is not emitted for
+        * placeholder devices.
         **/
        signals[DEVICE_REMOVED] =
                g_signal_new ("device-removed",
@@ -2368,6 +2450,38 @@ nm_client_class_init (NMClientClass *client_class)
                              G_TYPE_NONE, 1,
                              G_TYPE_OBJECT);
 
+       /**
+        * NMClient::any-device-added:
+        * @client: the client that received the signal
+        * @device: (type NMDevice): the new device
+        *
+        * Notifies that a #NMDevice is added.  This signal is emitted for both
+        * regular devices and placeholder devices.
+        **/
+       signals[ANY_DEVICE_ADDED] =
+               g_signal_new ("any-device-added",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0, NULL, NULL, NULL,
+                             G_TYPE_NONE, 1,
+                             G_TYPE_OBJECT);
+
+       /**
+        * NMClient::any-device-removed:
+        * @client: the client that received the signal
+        * @device: (type NMDevice): the removed device
+        *
+        * Notifies that a #NMDevice is removed.  This signal is emitted for both
+        * regular devices and placeholder devices.
+        **/
+       signals[ANY_DEVICE_REMOVED] =
+               g_signal_new ("any-device-removed",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0, NULL, NULL, NULL,
+                             G_TYPE_NONE, 1,
+                             G_TYPE_OBJECT);
+
        /**
         * NMClient::permission-changed:
         * @client: the client that received the signal
index ffe513c..39af321 100644 (file)
@@ -57,6 +57,7 @@ G_BEGIN_DECLS
 #define NM_CLIENT_PRIMARY_CONNECTION "primary-connection"
 #define NM_CLIENT_ACTIVATING_CONNECTION "activating-connection"
 #define NM_CLIENT_DEVICES "devices"
+#define NM_CLIENT_ALL_DEVICES "all-devices"
 
 /**
  * NMClientPermission:
@@ -175,6 +176,8 @@ NMClient *nm_client_new_finish (GAsyncResult         *result,
                                 GError              **error);
 
 const GPtrArray *nm_client_get_devices    (NMClient *client);
+NM_AVAILABLE_IN_1_2
+const GPtrArray *nm_client_get_all_devices(NMClient *client);
 NMDevice *nm_client_get_device_by_path    (NMClient *client, const char *object_path);
 NMDevice *nm_client_get_device_by_iface   (NMClient *client, const char *iface);
 
index 3b269e0..2c721f9 100644 (file)
@@ -686,6 +686,7 @@ typedef struct {
 static void
 da_check_quit (DaInfo *info)
 {
+       g_assert (info->quit_count > 0);
        info->quit_count--;
        if (info->quit_count == 0) {
                g_source_remove (info->quit_id);
index ae28769..e092a58 100644 (file)
@@ -861,6 +861,7 @@ global:
        nm_connection_get_setting_ip_tunnel;
        nm_connection_verify_secrets;
        nm_device_ethernet_get_s390_subchannels;
+       nm_client_get_all_devices;
        nm_device_get_lldp_neighbors;
        nm_device_get_metered;
        nm_device_ip_tunnel_get_encapsulation_limit;
@@ -897,6 +898,7 @@ global:
        nm_lldp_neighbor_new;
        nm_lldp_neighbor_ref;
        nm_lldp_neighbor_unref;
+       nm_manager_get_all_devices;
        nm_metered_get_type;
        nm_setting_802_1x_check_cert_scheme;
        nm_setting_bridge_get_multicast_snooping;
index e17042e..dc6db0a 100644 (file)
@@ -73,6 +73,7 @@ enum {
        PROP_PRIMARY_CONNECTION,
        PROP_ACTIVATING_CONNECTION,
        PROP_DEVICES,
+       PROP_ALL_DEVICES,
        PROP_CONNECTIONS,
        PROP_HOSTNAME,
        PROP_CAN_MODIFY,
@@ -84,6 +85,8 @@ enum {
 enum {
        DEVICE_ADDED,
        DEVICE_REMOVED,
+       ANY_DEVICE_ADDED,
+       ANY_DEVICE_REMOVED,
        PERMISSION_CHANGED,
        CONNECTION_ADDED,
        CONNECTION_REMOVED,
@@ -719,6 +722,34 @@ nm_client_get_devices (NMClient *client)
        return nm_manager_get_devices (NM_CLIENT_GET_PRIVATE (client)->manager);
 }
 
+/**
+ * nm_client_get_all_devices:
+ * @client: a #NMClient
+ *
+ * Gets both real devices and device placeholders (eg, software devices which
+ * do not currently exist, but could be created automatically by NetworkManager
+ * if one of their NMDevice::ActivatableConnections was activated).  Use
+ * nm_device_is_real() to determine whether each device is a real device or
+ * a placeholder.
+ *
+ * Use nm_device_get_type() or the NM_IS_DEVICE_XXXX() functions to determine
+ * what kind of device each member of the returned array is, and then you may
+ * use device-specific methods such as nm_device_ethernet_get_hw_address().
+ *
+ * Returns: (transfer none) (element-type NMDevice): a #GPtrArray
+ * containing all the #NMDevices.  The returned array is owned by the
+ * #NMClient object and should not be modified.
+ *
+ * Since: 1.2
+ **/
+const GPtrArray *
+nm_client_get_all_devices (NMClient *client)
+{
+       g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+       return nm_manager_get_all_devices (NM_CLIENT_GET_PRIVATE (client)->manager);
+}
+
 /**
  * nm_client_get_device_by_path:
  * @client: a #NMClient
@@ -1660,6 +1691,7 @@ manager_device_added (NMManager *manager,
 {
        g_signal_emit (client, signals[DEVICE_ADDED], 0, device);
 }
+
 static void
 manager_device_removed (NMManager *manager,
                         NMDevice *device,
@@ -1668,6 +1700,22 @@ manager_device_removed (NMManager *manager,
        g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
 }
 
+static void
+manager_any_device_added (NMManager *manager,
+                          NMDevice *device,
+                          gpointer client)
+{
+       g_signal_emit (client, signals[ANY_DEVICE_ADDED], 0, device);
+}
+
+static void
+manager_any_device_removed (NMManager *manager,
+                            NMDevice *device,
+                            gpointer client)
+{
+       g_signal_emit (client, signals[ANY_DEVICE_REMOVED], 0, device);
+}
+
 static void
 manager_permission_changed (NMManager *manager,
                             NMClientPermission permission,
@@ -1707,6 +1755,10 @@ constructed (GObject *object)
                          G_CALLBACK (manager_device_added), client);
        g_signal_connect (priv->manager, "device-removed",
                          G_CALLBACK (manager_device_removed), client);
+       g_signal_connect (priv->manager, "any-device-added",
+                         G_CALLBACK (manager_any_device_added), client);
+       g_signal_connect (priv->manager, "any-device-removed",
+                         G_CALLBACK (manager_any_device_removed), client);
        g_signal_connect (priv->manager, "permission-changed",
                          G_CALLBACK (manager_permission_changed), client);
 
@@ -1873,6 +1925,7 @@ get_property (GObject *object, guint prop_id,
        case PROP_ACTIVATING_CONNECTION:
        case PROP_DEVICES:
        case PROP_METERED:
+       case PROP_ALL_DEVICES:
                g_object_get_property (G_OBJECT (NM_CLIENT_GET_PRIVATE (object)->manager),
                                       pspec->name, value);
                break;
@@ -2092,7 +2145,7 @@ nm_client_class_init (NMClientClass *client_class)
        /**
         * NMClient:devices:
         *
-        * List of known network devices.
+        * List of real network devices.  Does not include placeholder devices.
         *
         * Element-type: NMDevice
         **/
@@ -2103,6 +2156,21 @@ nm_client_class_init (NMClientClass *client_class)
                                     G_PARAM_READABLE |
                                     G_PARAM_STATIC_STRINGS));
 
+       /**
+        * NMClient:all-devices:
+        *
+        * List of both real devices and device placeholders.
+        *
+        * Element-type: NMDevice
+        * Since: 1.2
+        **/
+       g_object_class_install_property
+               (object_class, PROP_ALL_DEVICES,
+                g_param_spec_boxed (NM_CLIENT_ALL_DEVICES, "", "",
+                                    G_TYPE_PTR_ARRAY,
+                                    G_PARAM_READABLE |
+                                    G_PARAM_STATIC_STRINGS));
+
        /**
         * NMClient:connections:
         *
@@ -2166,7 +2234,8 @@ nm_client_class_init (NMClientClass *client_class)
         * @client: the client that received the signal
         * @device: (type NMDevice): the new device
         *
-        * Notifies that a #NMDevice is added.
+        * Notifies that a #NMDevice is added.  This signal is not emitted for
+        * placeholder devices.
         **/
        signals[DEVICE_ADDED] =
                g_signal_new (NM_CLIENT_DEVICE_ADDED,
@@ -2182,7 +2251,8 @@ nm_client_class_init (NMClientClass *client_class)
         * @client: the client that received the signal
         * @device: (type NMDevice): the removed device
         *
-        * Notifies that a #NMDevice is removed.
+        * Notifies that a #NMDevice is removed.  This signal is not emitted for
+        * placeholder devices.
         **/
        signals[DEVICE_REMOVED] =
                g_signal_new (NM_CLIENT_DEVICE_REMOVED,
@@ -2193,6 +2263,40 @@ nm_client_class_init (NMClientClass *client_class)
                              G_TYPE_NONE, 1,
                              G_TYPE_OBJECT);
 
+       /**
+        * NMClient::any-device-added:
+        * @client: the client that received the signal
+        * @device: (type NMDevice): the new device
+        *
+        * Notifies that a #NMDevice is added.  This signal is emitted for both
+        * regular devices and placeholder devices.
+        **/
+       signals[ANY_DEVICE_ADDED] =
+               g_signal_new (NM_CLIENT_ANY_DEVICE_ADDED,
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (NMClientClass, any_device_added),
+                             NULL, NULL, NULL,
+                             G_TYPE_NONE, 1,
+                             G_TYPE_OBJECT);
+
+       /**
+        * NMClient::any-device-removed:
+        * @client: the client that received the signal
+        * @device: (type NMDevice): the removed device
+        *
+        * Notifies that a #NMDevice is removed.  This signal is emitted for both
+        * regular devices and placeholder devices.
+        **/
+       signals[ANY_DEVICE_REMOVED] =
+               g_signal_new (NM_CLIENT_ANY_DEVICE_REMOVED,
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (NMClientClass, any_device_removed),
+                             NULL, NULL, NULL,
+                             G_TYPE_NONE, 1,
+                             G_TYPE_OBJECT);
+
        /**
         * NMClient::permission-changed:
         * @client: the client that received the signal
index fc309fa..54d6dee 100644 (file)
@@ -53,6 +53,7 @@ G_BEGIN_DECLS
 #define NM_CLIENT_PRIMARY_CONNECTION "primary-connection"
 #define NM_CLIENT_ACTIVATING_CONNECTION "activating-connection"
 #define NM_CLIENT_DEVICES "devices"
+#define NM_CLIENT_ALL_DEVICES "all-devices"
 #define NM_CLIENT_CONNECTIONS "connections"
 #define NM_CLIENT_HOSTNAME "hostname"
 #define NM_CLIENT_CAN_MODIFY "can-modify"
@@ -60,6 +61,8 @@ G_BEGIN_DECLS
 
 #define NM_CLIENT_DEVICE_ADDED "device-added"
 #define NM_CLIENT_DEVICE_REMOVED "device-removed"
+#define NM_CLIENT_ANY_DEVICE_ADDED "any-device-added"
+#define NM_CLIENT_ANY_DEVICE_REMOVED "any-device-removed"
 #define NM_CLIENT_PERMISSION_CHANGED "permission-changed"
 #define NM_CLIENT_CONNECTION_ADDED "connection-added"
 #define NM_CLIENT_CONNECTION_REMOVED "connection-removed"
@@ -164,6 +167,8 @@ typedef struct {
        /* Signals */
        void (*device_added) (NMClient *client, NMDevice *device);
        void (*device_removed) (NMClient *client, NMDevice *device);
+       void (*any_device_added) (NMClient *client, NMDevice *device);
+       void (*any_device_removed) (NMClient *client, NMDevice *device);
        void (*permission_changed) (NMClient *client,
                                    NMClientPermission permission,
                                    NMClientPermissionResult result);
@@ -171,7 +176,7 @@ typedef struct {
        void (*connection_removed) (NMClient *client, NMRemoteConnection *connection);
 
        /*< private >*/
-       gpointer padding[8];
+       gpointer padding[6];
 } NMClientClass;
 
 GType nm_client_get_type (void);
@@ -248,6 +253,8 @@ gboolean nm_client_save_hostname_finish (NMClient *client,
 /* Devices */
 
 const GPtrArray *nm_client_get_devices    (NMClient *client);
+NM_AVAILABLE_IN_1_2
+const GPtrArray *nm_client_get_all_devices(NMClient *client);
 NMDevice *nm_client_get_device_by_path    (NMClient *client, const char *object_path);
 NMDevice *nm_client_get_device_by_iface   (NMClient *client, const char *iface);
 
index 7ed50e3..b4b7e0c 100644 (file)
@@ -60,6 +60,7 @@ typedef struct {
        NMState state;
        gboolean startup;
        GPtrArray *devices;
+       GPtrArray *all_devices;
        GPtrArray *active_connections;
        NMConnectivityState connectivity;
        NMActiveConnection *primary_connection;
@@ -104,6 +105,7 @@ enum {
        PROP_ACTIVATING_CONNECTION,
        PROP_DEVICES,
        PROP_METERED,
+       PROP_ALL_DEVICES,
 
        LAST_PROP
 };
@@ -111,6 +113,8 @@ enum {
 enum {
        DEVICE_ADDED,
        DEVICE_REMOVED,
+       ANY_DEVICE_ADDED,
+       ANY_DEVICE_REMOVED,
        ACTIVE_CONNECTION_ADDED,
        ACTIVE_CONNECTION_REMOVED,
        PERMISSION_CHANGED,
@@ -136,6 +140,7 @@ nm_manager_init (NMManager *manager)
 
        priv->permissions = g_hash_table_new (g_direct_hash, g_direct_equal);
        priv->devices = g_ptr_array_new ();
+       priv->all_devices = g_ptr_array_new ();
        priv->active_connections = g_ptr_array_new ();
 }
 
@@ -145,8 +150,8 @@ poke_wireless_devices_with_rf_status (NMManager *manager)
        NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
        int i;
 
-       for (i = 0; i < priv->devices->len; i++) {
-               NMDevice *device = g_ptr_array_index (priv->devices, i);
+       for (i = 0; i < priv->all_devices->len; i++) {
+               NMDevice *device = g_ptr_array_index (priv->all_devices, i);
 
                if (NM_IS_DEVICE_WIFI (device))
                        _nm_device_wifi_set_wireless_enabled (NM_DEVICE_WIFI (device), priv->wireless_enabled);
@@ -182,6 +187,7 @@ init_dbus (NMObject *object)
                { NM_MANAGER_ACTIVATING_CONNECTION,     &priv->activating_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
                { NM_MANAGER_DEVICES,                   &priv->devices, NULL, NM_TYPE_DEVICE, "device" },
                { NM_MANAGER_METERED,                   &priv->metered },
+               { NM_MANAGER_ALL_DEVICES,               &priv->all_devices, NULL, NM_TYPE_DEVICE, "any-device" },
                { NULL },
        };
 
@@ -667,6 +673,14 @@ nm_manager_get_devices (NMManager *manager)
        return NM_MANAGER_GET_PRIVATE (manager)->devices;
 }
 
+const GPtrArray *
+nm_manager_get_all_devices (NMManager *manager)
+{
+       g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
+
+       return NM_MANAGER_GET_PRIVATE (manager)->all_devices;
+}
+
 NMDevice *
 nm_manager_get_device_by_path (NMManager *manager, const char *object_path)
 {
@@ -1180,27 +1194,47 @@ static void
 free_devices (NMManager *manager, gboolean in_dispose)
 {
        NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-       GPtrArray *devices;
-       NMDevice *device;
-       int i;
+       gs_unref_ptrarray GPtrArray *real_devices = NULL;
+       gs_unref_ptrarray GPtrArray *all_devices = NULL;
+       GPtrArray *devices = NULL;
+       guint i, j;
 
-       if (!priv->devices)
+       real_devices = priv->devices;
+       all_devices = priv->all_devices;
+
+       if (in_dispose) {
+               priv->devices = NULL;
+               priv->all_devices = NULL;
                return;
+       }
 
-       devices = priv->devices;
+       priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
+       priv->all_devices = g_ptr_array_new_with_free_func (g_object_unref);
 
-       if (in_dispose)
-               priv->devices = NULL;
-       else {
-               priv->devices = g_ptr_array_new ();
+       if (all_devices && all_devices->len > 0)
+               devices = all_devices;
+       else if (devices && devices->len > 0)
+               devices = real_devices;
+
+       if (real_devices && devices != real_devices) {
+               for (i = 0; i < real_devices->len; i++) {
+                       NMDevice *d = real_devices->pdata[i];
 
-               for (i = 0; i < devices->len; i++) {
-                       device = devices->pdata[i];
-                       g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
+                       if (all_devices) {
+                               for (j = 0; j < all_devices->len; j++) {
+                                       if (d == all_devices->pdata[j])
+                                               goto next;
+                               }
+                       }
+                       g_signal_emit (manager, signals[DEVICE_REMOVED], 0, d);
+next:
+                       ;
                }
        }
-
-       g_ptr_array_unref (devices);
+       if (devices) {
+               for (i = 0; i < devices->len; i++)
+                       g_signal_emit (manager, signals[DEVICE_REMOVED], 0, devices->pdata[i]);
+       }
 }
 
 static void
@@ -1543,6 +1577,9 @@ get_property (GObject *object,
        case PROP_METERED:
                g_value_set_uint (value, priv->metered);
                break;
+       case PROP_ALL_DEVICES:
+               g_value_take_boxed (value, _nm_utils_copy_object_array (nm_manager_get_all_devices (self)));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -1689,6 +1726,13 @@ nm_manager_class_init (NMManagerClass *manager_class)
                                    G_PARAM_READABLE |
                                    G_PARAM_STATIC_STRINGS));
 
+       g_object_class_install_property
+               (object_class, PROP_ALL_DEVICES,
+                g_param_spec_boxed (NM_MANAGER_ALL_DEVICES, "", "",
+                                    G_TYPE_PTR_ARRAY,
+                                    G_PARAM_READABLE |
+                                    G_PARAM_STATIC_STRINGS));
+
        /* signals */
 
        signals[DEVICE_ADDED] =
@@ -1707,6 +1751,22 @@ nm_manager_class_init (NMManagerClass *manager_class)
                              NULL, NULL, NULL,
                              G_TYPE_NONE, 1,
                              G_TYPE_OBJECT);
+       signals[ANY_DEVICE_ADDED] =
+               g_signal_new ("any-device-added",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0,
+                             NULL, NULL, NULL,
+                             G_TYPE_NONE, 1,
+                             G_TYPE_OBJECT);
+       signals[ANY_DEVICE_REMOVED] =
+               g_signal_new ("any-device-removed",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0,
+                             NULL, NULL, NULL,
+                             G_TYPE_NONE, 1,
+                             G_TYPE_OBJECT);
        signals[ACTIVE_CONNECTION_ADDED] =
                g_signal_new ("active-connection-added",
                              G_OBJECT_CLASS_TYPE (object_class),
index 8d04a06..f9e4cd0 100644 (file)
@@ -51,6 +51,7 @@ G_BEGIN_DECLS
 #define NM_MANAGER_ACTIVATING_CONNECTION "activating-connection"
 #define NM_MANAGER_DEVICES "devices"
 #define NM_MANAGER_METERED "metered"
+#define NM_MANAGER_ALL_DEVICES "all-devices"
 
 typedef struct {
        NMObject parent;
@@ -67,6 +68,8 @@ typedef struct {
        void (*permission_changed) (NMManager *manager,
                                    NMClientPermission permission,
                                    NMClientPermissionResult result);
+
+       /* Beware: no more slots. Cannot extend struct without breaking ABI. */
 } NMManagerClass;
 
 GType nm_manager_get_type (void);
@@ -121,6 +124,8 @@ NMConnectivityState nm_manager_check_connectivity_finish (NMManager *manager,
 /* Devices */
 
 const GPtrArray *nm_manager_get_devices    (NMManager *manager);
+NM_AVAILABLE_IN_1_2
+const GPtrArray *nm_manager_get_all_devices(NMManager *manager);
 NMDevice *nm_manager_get_device_by_path    (NMManager *manager, const char *object_path);
 NMDevice *nm_manager_get_device_by_iface   (NMManager *manager, const char *iface);
 
index 94f8b28..ae63eaf 100755 (executable)
@@ -637,6 +637,7 @@ class UnknownConnectionException(dbus.DBusException):
     _dbus_error_name = IFACE_NM + '.UnknownConnection'
 
 PM_DEVICES = 'Devices'
+PM_ALL_DEVICES = 'AllDevices'
 PM_NETWORKING_ENABLED = 'NetworkingEnabled'
 PM_WWAN_ENABLED = 'WwanEnabled'
 PM_WWAN_HARDWARE_ENABLED = 'WwanHardwareEnabled'
@@ -681,6 +682,10 @@ class NetworkManager(ExportedObj):
     def GetDevices(self):
         return to_path_array(self.devices)
 
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao')
+    def GetAllDevices(self):
+        return to_path_array(self.devices)
+
     @dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o')
     def GetDeviceByIpIface(self, ip_iface):
         for d in self.devices:
@@ -798,6 +803,7 @@ class NetworkManager(ExportedObj):
     def add_device(self, device):
         self.devices.append(device)
         self.__notify(PM_DEVICES)
+        self.__notify(PM_ALL_DEVICES)
         self.DeviceAdded(to_path(device))
 
     @dbus.service.signal(IFACE_NM, signature='o')
@@ -807,12 +813,14 @@ class NetworkManager(ExportedObj):
     def remove_device(self, device):
         self.devices.remove(device)
         self.__notify(PM_DEVICES)
+        self.__notify(PM_ALL_DEVICES)
         self.DeviceRemoved(to_path(device))
 
     ################# D-Bus Properties interface
     def __get_props(self):
         props = {}
         props[PM_DEVICES] = to_path_array(self.devices)
+        props[PM_ALL_DEVICES] = to_path_array(self.devices)
         props[PM_NETWORKING_ENABLED] = True
         props[PM_WWAN_ENABLED] = True
         props[PM_WWAN_HARDWARE_ENABLED] = True