summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-01-08 11:55:03 -0600
committerDan Williams <dcbw@redhat.com>2014-01-23 17:34:12 -0600
commit4bf27b2e68b07a6e9c602df3705a31ce9edbca99 (patch)
tree6d4bc45e91f9f2d440f52ac1c2fae25885f5b501
parent452f8232b79687312451d4072c1d6bf0af25ee50 (diff)
downloadNetworkManager-4bf27b2e68b07a6e9c602df3705a31ce9edbca99.tar.gz
libnm-glib: add support for non-pseudo-property added/removed signals
With the addition of D-Bus properties for object-array properties in NetworkManager core, libnm-glib can use these properties instead of the pseudo-property stuff. However, we need to maintain API and provide individual added/removed signals for these properties, and that requires diff-ing the new and old object arrays. Add the infrastructure for doing that.
-rw-r--r--libnm-glib/nm-object-private.h1
-rw-r--r--libnm-glib/nm-object.c106
2 files changed, 100 insertions, 7 deletions
diff --git a/libnm-glib/nm-object-private.h b/libnm-glib/nm-object-private.h
index 1658c1dce5..171be10f70 100644
--- a/libnm-glib/nm-object-private.h
+++ b/libnm-glib/nm-object-private.h
@@ -37,6 +37,7 @@ typedef struct {
gpointer field;
PropertyMarshalFunc func;
GType object_type;
+ const char *signal_prefix;
} NMPropertiesInfo;
DBusGProxy *_nm_object_new_proxy (NMObject *self,
diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
index 127f2af6a6..4ec26f49d7 100644
--- a/libnm-glib/nm-object.c
+++ b/libnm-glib/nm-object.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <gio/gio.h>
#include <stdlib.h>
+#include <stdio.h>
#include <nm-utils.h>
#include "NetworkManager.h"
#include "nm-object.h"
@@ -52,8 +53,8 @@ static GHashTable *type_funcs, *type_async_funcs;
typedef struct {
PropertyMarshalFunc func;
GType object_type;
-
gpointer field;
+ const char *signal_prefix;
} PropertyInfo;
static void reload_complete (NMObject *object);
@@ -761,31 +762,121 @@ typedef struct {
const char *property_name;
} ObjectCreatedData;
+/* Places items from 'needles' that are not in 'haystack' into 'diff' */
+static void
+array_diff (GPtrArray *needles, GPtrArray *haystack, GPtrArray *diff)
+{
+ guint i, j;
+ GObject *obj;
+
+ g_assert (needles);
+ g_assert (haystack);
+ g_assert (diff);
+
+ for (i = 0; i < needles->len; i++) {
+ obj = g_ptr_array_index (needles, i);
+
+ for (j = 0; j < haystack->len; j++) {
+ if (g_ptr_array_index (haystack, j) == obj)
+ break;
+ }
+
+ if (j == haystack->len)
+ g_ptr_array_add (diff, obj);
+ }
+}
+
+static void
+emit_added_removed_signal (NMObject *self,
+ const char *signal_prefix,
+ NMObject *changed,
+ gboolean added)
+{
+ char buf[50];
+ int ret;
+
+ ret = snprintf (buf, sizeof (buf), "%s-%s", signal_prefix, added ? "added" : "removed");
+ g_assert (ret > 0);
+ g_assert (ret < sizeof (buf));
+ g_signal_emit_by_name (self, buf, changed);
+}
+
static void
object_property_complete (ObjectCreatedData *odata)
{
NMObject *self = odata->self;
NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
PropertyInfo *pi = odata->pi;
+ gboolean different = TRUE;
if (odata->array) {
- GPtrArray **array = pi->field;
+ GPtrArray *old = *((GPtrArray **) pi->field);
+ GPtrArray *new;
int i;
- if (*array)
- g_boxed_free (NM_TYPE_OBJECT_ARRAY, *array);
- *array = g_ptr_array_sized_new (odata->length);
+ /* Build up new array */
+ new = g_ptr_array_sized_new (odata->length);
for (i = 0; i < odata->length; i++)
- add_to_object_array_unique (*array, odata->objects[i]);
+ add_to_object_array_unique (new, odata->objects[i]);
+
+ if (pi->signal_prefix) {
+ GPtrArray *added = g_ptr_array_sized_new (3);
+ GPtrArray *removed = g_ptr_array_sized_new (3);
+
+ if (old) {
+ /* Find objects in 'old' that do not exist in 'new' */
+ array_diff (old, new, removed);
+
+ /* Find objects in 'new' that do not exist in old */
+ array_diff (new, old, added);
+ } else {
+ for (i = 0; i < new->len; i++)
+ g_ptr_array_add (added, g_ptr_array_index (new, i));
+ }
+
+ *((GPtrArray **) pi->field) = new;
+
+ /* Emit added & removed */
+ for (i = 0; i < removed->len; i++) {
+ emit_added_removed_signal (self,
+ pi->signal_prefix,
+ g_ptr_array_index (removed, i),
+ FALSE);
+ }
+
+ for (i = 0; i < added->len; i++) {
+ emit_added_removed_signal (self,
+ pi->signal_prefix,
+ g_ptr_array_index (added, i),
+ TRUE);
+ }
+
+ different = removed->len || added->len;
+ g_ptr_array_free (added, TRUE);
+ g_ptr_array_free (removed, TRUE);
+ } else {
+ /* No added/removed signals to send, just replace the property with
+ * the new values.
+ */
+ *((GPtrArray **) pi->field) = new;
+ different = TRUE;
+ }
+
+ /* Free old array last since it will release references, thus freeing
+ * any objects in the 'removed' array.
+ */
+ if (old)
+ g_boxed_free (NM_TYPE_OBJECT_ARRAY, old);
} else {
GObject **obj_p = pi->field;
+ different = (*obj_p != odata->objects[0]);
if (*obj_p)
g_object_unref (*obj_p);
*obj_p = odata->objects[0];
}
- if (odata->property_name)
+ if (different && odata->property_name)
_nm_object_queue_notify (self, odata->property_name);
if (priv->reload_results && --priv->reload_remaining == 0)
@@ -1135,6 +1226,7 @@ _nm_object_register_properties (NMObject *object,
pi->func = tmp->func ? tmp->func : demarshal_generic;
pi->object_type = tmp->object_type;
pi->field = tmp->field;
+ pi->signal_prefix = tmp->signal_prefix;
g_hash_table_insert (instance, g_strdup (tmp->name), pi);
}
}