nm-manager: add 'metered' property
authorBeniamino Galvani <bgalvani@redhat.com>
Wed, 3 Jun 2015 07:15:24 +0000 (09:15 +0200)
committerBeniamino Galvani <bgalvani@redhat.com>
Tue, 9 Jun 2015 16:23:19 +0000 (18:23 +0200)
This introduces a global metered property which makes easier for
clients to obtain the metered status of the current primary
connection.

introspection/nm-manager.xml
libnm/nm-client.c
libnm/nm-client.h
libnm/nm-manager.c
libnm/nm-manager.h
src/nm-active-connection.c
src/nm-active-connection.h
src/nm-manager.c
src/nm-manager.h

index a9bb6dc..f0d0443 100644 (file)
       </tp:docstring>
     </property>
 
+    <property name="Metered" type="u" access="read" tp:type="NM_METERED">
+      <tp:docstring>
+        Wheter the connectivity is metered. This is equivalent to the
+        metered property of the device associated with the primary
+        connection.
+      </tp:docstring>
+    </property>
+
     <property name="ActivatingConnection" type="o" access="read">
       <tp:docstring>
         The object path of an active connection that is currently
index e0a2a7b..3d683a1 100644 (file)
@@ -76,6 +76,7 @@ enum {
        PROP_CONNECTIONS,
        PROP_HOSTNAME,
        PROP_CAN_MODIFY,
+       PROP_METERED,
 
        LAST_PROP
 };
@@ -1871,6 +1872,7 @@ get_property (GObject *object, guint prop_id,
        case PROP_PRIMARY_CONNECTION:
        case PROP_ACTIVATING_CONNECTION:
        case PROP_DEVICES:
+       case PROP_METERED:
                g_object_get_property (G_OBJECT (NM_CLIENT_GET_PRIVATE (object)->manager),
                                       pspec->name, value);
                break;
@@ -2143,6 +2145,20 @@ nm_client_class_init (NMClientClass *client_class)
                                       G_PARAM_READABLE |
                                       G_PARAM_STATIC_STRINGS));
 
+       /**
+        * NMClient:metered:
+        *
+        * Whether the connectivity is metered.
+        *
+        * Since: 1.2
+        **/
+       g_object_class_install_property
+               (object_class, PROP_METERED,
+                g_param_spec_uint (NM_CLIENT_METERED, "", "",
+                                   0, G_MAXUINT32, NM_METERED_UNKNOWN,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS));
+
        /* signals */
 
        /**
index 619ad85..fc309fa 100644 (file)
@@ -56,6 +56,7 @@ G_BEGIN_DECLS
 #define NM_CLIENT_CONNECTIONS "connections"
 #define NM_CLIENT_HOSTNAME "hostname"
 #define NM_CLIENT_CAN_MODIFY "can-modify"
+#define NM_CLIENT_METERED "metered"
 
 #define NM_CLIENT_DEVICE_ADDED "device-added"
 #define NM_CLIENT_DEVICE_REMOVED "device-removed"
index 003d6b8..2fd4027 100644 (file)
@@ -64,6 +64,7 @@ typedef struct {
        NMConnectivityState connectivity;
        NMActiveConnection *primary_connection;
        NMActiveConnection *activating_connection;
+       NMMetered metered;
 
        GCancellable *perm_call_cancellable;
        GHashTable *permissions;
@@ -102,6 +103,7 @@ enum {
        PROP_PRIMARY_CONNECTION,
        PROP_ACTIVATING_CONNECTION,
        PROP_DEVICES,
+       PROP_METERED,
 
        LAST_PROP
 };
@@ -179,6 +181,7 @@ init_dbus (NMObject *object)
                { NM_MANAGER_PRIMARY_CONNECTION,        &priv->primary_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
                { 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 },
                { NULL },
        };
 
@@ -1537,6 +1540,9 @@ get_property (GObject *object,
        case PROP_DEVICES:
                g_value_take_boxed (value, _nm_utils_copy_object_array (nm_manager_get_devices (self)));
                break;
+       case PROP_METERED:
+               g_value_set_uint (value, priv->metered);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -1669,6 +1675,19 @@ nm_manager_class_init (NMManagerClass *manager_class)
                                     G_TYPE_PTR_ARRAY,
                                     G_PARAM_READABLE |
                                     G_PARAM_STATIC_STRINGS));
+       /**
+        * NMManager:metered:
+        *
+        * Whether the connectivity is metered.
+        *
+        * Since: 1.2
+        **/
+       g_object_class_install_property
+               (object_class, PROP_METERED,
+                g_param_spec_uint (NM_MANAGER_METERED, "", "",
+                                   0, G_MAXUINT32, NM_METERED_UNKNOWN,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS));
 
        /* signals */
 
index ca9f7dd..8d04a06 100644 (file)
@@ -50,6 +50,7 @@ G_BEGIN_DECLS
 #define NM_MANAGER_PRIMARY_CONNECTION "primary-connection"
 #define NM_MANAGER_ACTIVATING_CONNECTION "activating-connection"
 #define NM_MANAGER_DEVICES "devices"
+#define NM_MANAGER_METERED "metered"
 
 typedef struct {
        NMObject parent;
index d0b5b87..2b72961 100644 (file)
@@ -100,6 +100,7 @@ enum {
 
 enum {
        DEVICE_CHANGED,
+       DEVICE_METERED_CHANGED,
        LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -401,6 +402,18 @@ device_master_changed (GObject *object,
        }
 }
 
+static void
+device_metered_changed (GObject *object,
+                        GParamSpec *pspec,
+                        gpointer user_data)
+{
+       NMActiveConnection *self = (NMActiveConnection *) user_data;
+       NMDevice *device = NM_DEVICE (object);
+
+       g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
+       g_signal_emit (self, signals[DEVICE_METERED_CHANGED], 0, nm_device_get_metered (device));
+}
+
 gboolean
 nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
 {
@@ -427,6 +440,8 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
                                  G_CALLBACK (device_state_changed), self);
                g_signal_connect (device, "notify::master",
                                  G_CALLBACK (device_master_changed), self);
+               g_signal_connect (device, "notify::" NM_DEVICE_METERED,
+                                 G_CALLBACK (device_metered_changed), self);
 
                if (!priv->assumed) {
                        priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
@@ -837,6 +852,7 @@ _device_cleanup (NMActiveConnection *self)
        if (priv->device) {
                g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_state_changed), self);
                g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_master_changed), self);
+               g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_metered_changed), self);
        }
 
        if (priv->pending_activation_id) {
@@ -1042,6 +1058,14 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
                              NULL, NULL, NULL,
                              G_TYPE_NONE, 2, NM_TYPE_DEVICE, NM_TYPE_DEVICE);
 
+       signals[DEVICE_METERED_CHANGED] =
+               g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED,
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (NMActiveConnectionClass, device_metered_changed),
+                             NULL, NULL, NULL,
+                             G_TYPE_NONE, 1, G_TYPE_UINT);
+
        nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
                                                G_TYPE_FROM_CLASS (ac_class),
                                                &dbus_glib_nm_active_connection_object_info);
index 710cfee..4db5e6f 100644 (file)
@@ -57,7 +57,8 @@
 #define NM_ACTIVE_CONNECTION_INT_MASTER_READY   "int-master-ready"
 
 /* Internal signals*/
-#define NM_ACTIVE_CONNECTION_DEVICE_CHANGED     "device-changed"
+#define NM_ACTIVE_CONNECTION_DEVICE_CHANGED          "device-changed"
+#define NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED  "device-metered-changed"
 
 struct _NMActiveConnection {
        GObject parent;
@@ -78,6 +79,9 @@ typedef struct {
        void (*device_changed) (NMActiveConnection *connection,
                                NMDevice *new_device,
                                NMDevice *old_device);
+
+       void (*device_metered_changed) (NMActiveConnection *connection,
+                                       NMMetered new_value);
 } NMActiveConnectionClass;
 
 GType         nm_active_connection_get_type (void);
index 5e2aff8..bf9e69a 100644 (file)
@@ -157,6 +157,7 @@ typedef struct {
        guint ac_cleanup_id;
        NMActiveConnection *primary_connection;
        NMActiveConnection *activating_connection;
+       NMMetered metered;
 
        GSList *devices;
        NMState state;
@@ -230,6 +231,7 @@ enum {
        PROP_PRIMARY_CONNECTION_TYPE,
        PROP_ACTIVATING_CONNECTION,
        PROP_DEVICES,
+       PROP_METERED,
 
        /* Not exported */
        PROP_HOSTNAME,
@@ -654,6 +656,30 @@ find_best_device_state (NMManager *manager)
        return best_state;
 }
 
+static void
+nm_manager_update_metered (NMManager *manager)
+{
+       NMManagerPrivate *priv;
+       NMDevice *device;
+       NMMetered value = NM_METERED_UNKNOWN;
+
+       g_return_if_fail (NM_IS_MANAGER (manager));
+       priv = NM_MANAGER_GET_PRIVATE (manager);
+
+       if (priv->primary_connection) {
+               device =  nm_active_connection_get_device (priv->primary_connection);
+               if (device)
+                       value = nm_device_get_metered (device);
+       }
+
+       if (value != priv->metered) {
+               priv->metered = value;
+               nm_log_dbg (LOGD_CORE, "New manager metered value: %d",
+                           (int) priv->metered);
+               g_object_notify (G_OBJECT (manager), NM_MANAGER_METERED);
+       }
+}
+
 static void
 nm_manager_update_state (NMManager *manager)
 {
@@ -4055,6 +4081,14 @@ firmware_dir_changed (GFileMonitor *monitor,
        }
 }
 
+static void
+connection_metered_changed (GObject *object,
+                            NMMetered metered,
+                            gpointer user_data)
+{
+       nm_manager_update_metered (NM_MANAGER (user_data));
+}
+
 static void
 policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
 {
@@ -4077,11 +4111,23 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user
                ac = NULL;
 
        if (ac != priv->primary_connection) {
-               g_clear_object (&priv->primary_connection);
+               if (priv->primary_connection) {
+                       g_signal_handlers_disconnect_by_func (priv->primary_connection,
+                                                             G_CALLBACK (connection_metered_changed),
+                                                             self);
+                       g_clear_object (&priv->primary_connection);
+               }
+
                priv->primary_connection = ac ? g_object_ref (ac) : NULL;
+
+               if (priv->primary_connection) {
+                       g_signal_connect (priv->primary_connection, NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED,
+                                         G_CALLBACK (connection_metered_changed), self);
+               }
                nm_log_dbg (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_id (ac) : "(none)");
                g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION);
                g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION_TYPE);
+               nm_manager_update_metered (self);
        }
 }
 
@@ -4649,6 +4695,8 @@ nm_manager_init (NMManager *manager)
 
        /* Update timestamps in active connections */
        priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, manager);
+
+       priv->metered = NM_METERED_UNKNOWN;
 }
 
 static void
@@ -4733,6 +4781,9 @@ get_property (GObject *object, guint prop_id,
                }
                g_value_take_boxed (value, array);
                break;
+       case PROP_METERED:
+               g_value_set_uint (value, priv->metered);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -5011,6 +5062,20 @@ nm_manager_class_init (NMManagerClass *manager_class)
                                     G_PARAM_READABLE |
                                     G_PARAM_STATIC_STRINGS));
 
+       /**
+        * NMManager:metered:
+        *
+        * Whether the connectivity is metered.
+        *
+        * Since: 1.2
+        **/
+       g_object_class_install_property
+               (object_class, PROP_METERED,
+                g_param_spec_uint (NM_MANAGER_METERED, "", "",
+                                   0, G_MAXUINT32, NM_METERED_UNKNOWN,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS));
+
        /* signals */
        signals[DEVICE_ADDED] =
                g_signal_new ("device-added",
index 3b00e80..a8e7d7a 100644 (file)
@@ -51,6 +51,7 @@
 #define NM_MANAGER_PRIMARY_CONNECTION_TYPE "primary-connection-type"
 #define NM_MANAGER_ACTIVATING_CONNECTION "activating-connection"
 #define NM_MANAGER_DEVICES "devices"
+#define NM_MANAGER_METERED "metered"
 
 /* Not exported */
 #define NM_MANAGER_HOSTNAME "hostname"