summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@redhat.com>2015-04-15 14:53:30 -0400
committerDan Winship <danw@redhat.com>2015-08-10 09:41:26 -0400
commit073991f5a8271a1e7367ec330fc7c8cf54522ffb (patch)
tree5c95ab7c42d66eb5ebe7902f2ae2e7831bea35a9
parent284e15a8775e487e094be7e327582d45a903af99 (diff)
core: port NMExportedObject to gdbus
Port NMExportedObject to gdbus, and make nm_exported_object_class_add_interface() deal with generating D-Bus skeleton objects and attaching signal handlers and property bindings as needed to properly handle methods, signals, and properties.
-rw-r--r--src/nm-exported-object.c539
-rw-r--r--src/nm-exported-object.h6
2 files changed, 424 insertions, 121 deletions
diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c
index 9ad734d8af..83aecaca27 100644
--- a/src/nm-exported-object.c
+++ b/src/nm-exported-object.c
@@ -20,10 +20,10 @@
#include "config.h"
+#include <stdarg.h>
#include <string.h>
#include "nm-exported-object.h"
-#include "nm-dbus-glib-types.h"
#include "nm-bus-manager.h"
#include "nm-default.h"
@@ -34,85 +34,374 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (NMExportedObject, nm_exported_object, G_TYPE_O
)
typedef struct {
+ GSList *interfaces;
+
char *path;
- GHashTable *pending_notifies;
+ GVariantBuilder pending_notifies;
guint notify_idle_id;
} NMExportedObjectPrivate;
#define NM_EXPORTED_OBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_EXPORTED_OBJECT, NMExportedObjectPrivate))
-enum {
- PROPERTIES_CHANGED,
-
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
+typedef struct {
+ GType dbus_skeleton_type;
+ char *method_name;
+ GCallback impl;
+} NMExportedObjectDBusMethodImpl;
typedef struct {
GHashTable *properties;
+ GSList *skeleton_types;
+ GArray *methods;
} NMExportedObjectClassInfo;
GQuark nm_exported_object_class_info_quark (void);
G_DEFINE_QUARK (NMExportedObjectClassInfo, nm_exported_object_class_info)
+/* "AddConnectionUnsaved" -> "handle-add-connection-unsaved" */
+static char *
+skeletonify_method_name (const char *dbus_method_name)
+{
+ GString *out;
+ const char *p;
+
+ out = g_string_new ("handle");
+ for (p = dbus_method_name; *p; p++) {
+ if (g_ascii_isupper (*p) || p == dbus_method_name) {
+ g_string_append_c (out, '-');
+ g_string_append_c (out, g_ascii_tolower (*p));
+ } else
+ g_string_append_c (out, *p);
+ }
+
+ return g_string_free (out, FALSE);
+}
+
+/* "can-modify" -> "CanModify" */
+static char *
+dbusify_name (const char *gobject_name)
+{
+ GString *out;
+ const char *p;
+ gboolean capitalize = TRUE;
+
+ out = g_string_new ("");
+ for (p = gobject_name; *p; p++) {
+ if (capitalize) {
+ g_string_append_c (out, g_ascii_toupper (*p));
+ capitalize = FALSE;
+ } else if (*p == '-')
+ capitalize = TRUE;
+ else
+ g_string_append_c (out, *p);
+ }
+
+ return g_string_free (out, FALSE);
+}
+
+/* "can_modify" -> "can-modify". Returns %NULL if @gobject_name contains no underscores */
+static char *
+hyphenify_name (const char *gobject_name)
+{
+ char *hyphen_name, *p;
+
+ if (!strchr (gobject_name, '_'))
+ return NULL;
+
+ hyphen_name = g_strdup (gobject_name);
+ for (p = hyphen_name; *p; p++) {
+ if (*p == '_')
+ *p = '-';
+ }
+ return hyphen_name;
+}
+
+/* Called when an #NMExportedObject emits a signal that corresponds to a D-Bus
+ * signal, and re-emits that signal on the correct skeleton object as well.
+ */
+static gboolean
+nm_exported_object_signal_hook (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ NMExportedObject *self = g_value_get_object (&param_values[0]);
+ NMExportedObjectPrivate *priv;
+ GSignalQuery *signal_info = data;
+ GDBusObjectSkeleton *interface = NULL;
+ GSList *iter;
+ GValue *dbus_param_values;
+ int i;
+
+ priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
+ if (!priv->path)
+ return TRUE;
+
+ for (iter = priv->interfaces; iter; iter = iter->next) {
+ if (g_type_is_a (G_OBJECT_TYPE (iter->data), signal_info->itype)) {
+ interface = iter->data;
+ break;
+ }
+ }
+ g_return_val_if_fail (interface != NULL, TRUE);
+
+ dbus_param_values = g_new0 (GValue, n_param_values);
+ g_value_init (&dbus_param_values[0], G_OBJECT_TYPE (interface));
+ g_value_set_object (&dbus_param_values[0], interface);
+ for (i = 1; i < n_param_values; i++) {
+ if (g_type_is_a (param_values[i].g_type, NM_TYPE_EXPORTED_OBJECT)) {
+ NMExportedObject *arg = g_value_get_object (&param_values[i]);
+
+ g_value_init (&dbus_param_values[i], G_TYPE_STRING);
+ if (arg && nm_exported_object_is_exported (arg))
+ g_value_set_string (&dbus_param_values[i], nm_exported_object_get_path (arg));
+ else
+ g_value_set_string (&dbus_param_values[i], "/");
+ } else {
+ g_value_init (&dbus_param_values[i], param_values[i].g_type);
+ g_value_copy (&param_values[i], &dbus_param_values[i]);
+ }
+ }
+
+ g_signal_emitv (dbus_param_values, signal_info->signal_id, 0, NULL);
+
+ for (i = 0; i < n_param_values; i++)
+ g_value_unset (&dbus_param_values[i]);
+ g_free (dbus_param_values);
+
+ return TRUE;
+}
+
/**
* nm_exported_object_class_add_interface:
* @object_class: an #NMExportedObjectClass
- * @info: generated #DBusGObjectInfo for the class
+ * @dbus_skeleton_type: the type of the #GDBusObjectSkeleton to add
+ * @...: method name / handler pairs, %NULL-terminated
+ *
+ * Adds @dbus_skeleton_type to the list of D-Bus interfaces implemented by
+ * @object_class. Instances of @object_class will automatically have a skeleton
+ * of that type created, which will be exported when you call
+ * nm_exported_object_export().
+ *
+ * The skeleton's properties will be initialized from the #NMExportedObject's,
+ * and bidirectional bindings will be set up between them. When exported
+ * properties change, both the org.freedesktop.DBus.Properties.PropertiesChanged
+ * signal and the traditional NetworkManager PropertiesChanged signal will be
+ * emitted.
+ *
+ * When a signal is emitted on an #NMExportedObject that has the same name as a
+ * signal on @dbus_skeleton_type, it will automatically be emitted on the
+ * skeleton as well; #NMExportedObject arguments in the signal will be converted
+ * to D-Bus object paths in the skeleton signal.
*
- * Adds @info to the list of D-Bus interfaces implemented by @object_class and
- * sets up automatic dbus-glib handling for instances of that class.
+ * The arguments after @dbus_skeleton_type are pairs of D-Bus method names (in
+ * CamelCase), and the corresponding handlers for them (which must have the same
+ * prototype as the corresponding "handle-..." signal on @dbus_skeleton_type,
+ * except with no return value, and with the first argument being an object of
+ * @object_class's type, not of @dbus_skeleton_type).
*
- * If @info includes any properties, then a "PropertiesChanged" signal will
- * be emitted on @info's interface whenever any of those properties change on
- * an exported instance of @object_class.
+ * It is a programmer error if:
+ * - @object_class does not define a property of the same name and type as
+ * each of @dbus_skeleton_type's properties.
+ * - @object_class does not define a signal with the same name and arguments
+ * as each of @dbus_skeleton_type's signals.
+ * - the list of method names includes any names that do not correspond to
+ * "handle-" signals on @dbus_skeleton_type.
+ * - the list of method names does not include every method defined by
+ * @dbus_skeleton_type.
*/
void
nm_exported_object_class_add_interface (NMExportedObjectClass *object_class,
- const DBusGObjectInfo *info)
+ GType dbus_skeleton_type,
+ ...)
{
- GType object_type = G_TYPE_FROM_CLASS (object_class);
NMExportedObjectClassInfo *classinfo;
- const char *properties_info, *dbus_name, *gobject_name, *tmp_access;
- char *hyphen_name, *p;
+ NMExportedObjectDBusMethodImpl method;
+ va_list ap;
+ const char *method_name;
+ GCallback impl;
+ GType *interfaces;
+ guint n_interfaces;
+ guint *dbus_signals, n_signals, n_method_signals;
+ guint object_signal_id;
+ GSignalQuery query;
+ int i, s;
+ GObjectClass *dbus_object_class;
+ GParamSpec **dbus_properties, *object_property;
+ guint n_dbus_properties;
+
+ g_return_if_fail (NM_IS_EXPORTED_OBJECT_CLASS (object_class));
+ g_return_if_fail (g_type_is_a (dbus_skeleton_type, G_TYPE_DBUS_INTERFACE_SKELETON));
+
+ classinfo = g_slice_new (NMExportedObjectClassInfo);
+ classinfo->skeleton_types = NULL;
+ classinfo->methods = g_array_new (FALSE, FALSE, sizeof (NMExportedObjectDBusMethodImpl));
+ classinfo->properties = g_hash_table_new (g_str_hash, g_str_equal);
+ g_type_set_qdata (G_TYPE_FROM_CLASS (object_class),
+ nm_exported_object_class_info_quark (), classinfo);
+
+ classinfo->skeleton_types = g_slist_prepend (classinfo->skeleton_types,
+ GSIZE_TO_POINTER (dbus_skeleton_type));
+
+ /* Ensure @dbus_skeleton_type's class_init has run, so its signals/properties
+ * will be defined.
+ */
+ dbus_object_class = g_type_class_ref (dbus_skeleton_type);
+
+ /* Add method implementations from the varargs */
+ va_start (ap, dbus_skeleton_type);
+ while ((method_name = va_arg (ap, const char *)) && (impl = va_arg (ap, GCallback))) {
+ method.dbus_skeleton_type = dbus_skeleton_type;
+ method.method_name = skeletonify_method_name (method_name);
+ g_assert (g_signal_lookup (method.method_name, dbus_skeleton_type) != 0);
+ method.impl = impl;
+
+ g_array_append_val (classinfo->methods, method);
+ }
+ va_end (ap);
- dbus_g_object_type_install_info (object_type, info);
- if (!info->exported_properties)
- return;
+ /* Properties */
+ dbus_properties = g_object_class_list_properties (dbus_object_class, &n_dbus_properties);
+ for (i = 0; i < n_dbus_properties; i++) {
+ char *hyphen_name;
- classinfo = g_type_get_qdata (object_type, nm_exported_object_class_info_quark ());
- if (!classinfo) {
- classinfo = g_slice_new (NMExportedObjectClassInfo);
- classinfo->properties = g_hash_table_new (g_str_hash, g_str_equal);
- g_type_set_qdata (object_type, nm_exported_object_class_info_quark (), classinfo);
- }
+ if (g_str_has_prefix (dbus_properties[i]->name, "g-"))
+ continue;
- properties_info = info->exported_properties;
- while (*properties_info) {
- /* The format is: "interface\0DBusPropertyName\0gobject_property_name\0access\0" */
- dbus_name = strchr (properties_info, '\0') + 1;
- gobject_name = strchr (dbus_name, '\0') + 1;
- tmp_access = strchr (gobject_name, '\0') + 1;
- properties_info = strchr (tmp_access, '\0') + 1;
-
- if (strchr (gobject_name, '_')) {
- hyphen_name = g_strdup (gobject_name);
- for (p = hyphen_name; *p; p++) {
- if (*p == '_')
- *p = '-';
- }
+ object_property = g_object_class_find_property (G_OBJECT_CLASS (object_class),
+ dbus_properties[i]->name);
+ g_assert (object_property != NULL);
+ g_assert (object_property->value_type == dbus_properties[i]->value_type);
+
+ g_assert (!g_hash_table_contains (classinfo->properties, dbus_properties[i]->name));
+ g_hash_table_insert (classinfo->properties,
+ g_strdup (dbus_properties[i]->name),
+ dbusify_name (dbus_properties[i]->name));
+ hyphen_name = hyphenify_name (dbus_properties[i]->name);
+ if (hyphen_name) {
g_assert (!g_hash_table_contains (classinfo->properties, hyphen_name));
g_hash_table_insert (classinfo->properties,
- (char *) g_intern_string (hyphen_name),
- (char *) dbus_name);
- g_free (hyphen_name);
- } else {
- g_assert (!g_hash_table_contains (classinfo->properties, (char *) gobject_name));
- g_hash_table_insert (classinfo->properties,
- (char *) gobject_name,
- (char *) dbus_name);
+ hyphen_name,
+ dbusify_name (dbus_properties[i]->name));
+ }
+ }
+
+ /* Signals. Unlike g_object_class_list_properties(), g_signal_list_ids() is
+ * "shallow", so we need to query each implemented gdbus-generated interface
+ * separately.
+ */
+ interfaces = g_type_interfaces (dbus_skeleton_type, &n_interfaces);
+ n_method_signals = 0;
+ for (i = 0; i < n_interfaces; i++) {
+ dbus_signals = g_signal_list_ids (interfaces[i], &n_signals);
+ for (s = 0; s < n_signals; s++) {
+ g_signal_query (dbus_signals[s], &query);
+
+ /* PropertiesChanged is handled specially */
+ if (!strcmp (query.signal_name, "properties-changed"))
+ continue;
+
+ if (g_str_has_prefix (query.signal_name, "handle-")) {
+ n_method_signals++;
+ continue;
+ }
+
+ object_signal_id = g_signal_lookup (query.signal_name, G_TYPE_FROM_CLASS (object_class));
+ g_assert (object_signal_id != 0);
+
+ g_signal_add_emission_hook (object_signal_id, 0,
+ nm_exported_object_signal_hook,
+ g_memdup (&query, sizeof (query)),
+ g_free);
+ }
+ }
+
+ g_assert_cmpint (n_method_signals, ==, classinfo->methods->len);
+
+ g_type_class_unref (dbus_object_class);
+}
+
+/* "meta-marshaller" that receives the skeleton "handle-foo" signal, replaces
+ * the skeleton object with an #NMExportedObject in the parameters, drops the
+ * user_data parameter, and adds a "TRUE" return value (indicating to gdbus that
+ * the signal was handled).
+ */
+static void
+nm_exported_object_meta_marshal (GClosure *closure, GValue *return_value,
+ guint n_param_values, const GValue *param_values,
+ gpointer invocation_hint, gpointer marshal_data)
+{
+ GValue *local_param_values;
+
+ local_param_values = g_new0 (GValue, n_param_values);
+ g_value_init (&local_param_values[0], G_TYPE_POINTER);
+ g_value_set_pointer (&local_param_values[0], closure->data);
+ memcpy (local_param_values + 1, param_values + 1, (n_param_values - 1) * sizeof (GValue));
+
+ g_cclosure_marshal_generic (closure, NULL,
+ n_param_values, local_param_values,
+ invocation_hint,
+ ((GCClosure *)closure)->callback);
+ g_value_set_boolean (return_value, TRUE);
+
+ g_value_unset (&local_param_values[0]);
+ g_free (local_param_values);
+}
+
+static void
+nm_exported_object_create_skeletons (NMExportedObject *self,
+ GType object_type)
+{
+ NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
+ GObjectClass *object_class = g_type_class_peek (object_type);
+ NMExportedObjectClassInfo *classinfo;
+ GSList *iter;
+ GDBusObjectSkeleton *interface;
+ GParamSpec **properties;
+ guint n_properties;
+ int i;
+
+ classinfo = g_type_get_qdata (object_type, nm_exported_object_class_info_quark ());
+ if (!classinfo)
+ return;
+
+ for (iter = classinfo->skeleton_types; iter; iter = iter->next) {
+ GType dbus_skeleton_type = GPOINTER_TO_SIZE (iter->data);
+
+ interface = g_object_new (dbus_skeleton_type, NULL);
+ priv->interfaces = g_slist_prepend (priv->interfaces, interface);
+
+ /* Bind properties */
+ properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (interface), &n_properties);
+ for (i = 0; i < n_properties; i++) {
+ GParamSpec *nm_property;
+ GBindingFlags flags;
+
+ nm_property = g_object_class_find_property (object_class, properties[i]->name);
+ if (!nm_property)
+ continue;
+
+ flags = G_BINDING_SYNC_CREATE;
+ if ( (nm_property->flags & G_PARAM_WRITABLE)
+ && !(nm_property->flags & G_PARAM_CONSTRUCT_ONLY))
+ flags |= G_BINDING_BIDIRECTIONAL;
+ g_object_bind_property (self, properties[i]->name,
+ interface, properties[i]->name,
+ flags);
+ }
+
+ /* Bind methods */
+ for (i = 0; i < classinfo->methods->len; i++) {
+ NMExportedObjectDBusMethodImpl *method = &g_array_index (classinfo->methods, NMExportedObjectDBusMethodImpl, i);
+ GClosure *closure;
+
+ if (method->dbus_skeleton_type != dbus_skeleton_type)
+ continue;
+
+ closure = g_cclosure_new_swap (method->impl, self, NULL);
+ g_closure_set_meta_marshal (closure, NULL, nm_exported_object_meta_marshal);
+ g_signal_connect_closure (interface, method->method_name, closure, FALSE);
}
}
}
@@ -135,7 +424,10 @@ const char *
nm_exported_object_export (NMExportedObject *self)
{
NMExportedObjectPrivate *priv;
+ NMBusManager *dbus_manager = nm_bus_manager_get ();
const char *class_export_path, *p;
+ GSList *iter;
+ GType type;
g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), NULL);
priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
@@ -160,7 +452,14 @@ nm_exported_object_export (NMExportedObject *self)
} else
priv->path = g_strdup (class_export_path);
- nm_bus_manager_register_object (nm_bus_manager_get (), priv->path, self);
+ type = G_OBJECT_TYPE (self);
+ while (type != NM_TYPE_EXPORTED_OBJECT) {
+ nm_exported_object_create_skeletons (self, type);
+ type = g_type_parent (type);
+ }
+
+ for (iter = priv->interfaces; iter; iter = iter->next)
+ nm_bus_manager_register_object (dbus_manager, priv->path, iter->data);
return priv->path;
}
@@ -208,6 +507,7 @@ void
nm_exported_object_unexport (NMExportedObject *self)
{
NMExportedObjectPrivate *priv;
+ GSList *iter;
g_return_if_fail (NM_IS_EXPORTED_OBJECT (self));
priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
@@ -215,16 +515,11 @@ nm_exported_object_unexport (NMExportedObject *self)
g_return_if_fail (priv->path != NULL);
g_clear_pointer (&priv->path, g_free);
- nm_bus_manager_unregister_object (nm_bus_manager_get (), self);
-}
-static void
-destroy_value (gpointer data)
-{
- GValue *val = (GValue *) data;
-
- g_value_unset (val);
- g_slice_free (GValue, val);
+ for (iter = priv->interfaces; iter; iter = iter->next)
+ nm_bus_manager_unregister_object (nm_bus_manager_get (), iter->data);
+ g_slist_free_full (priv->interfaces, g_object_unref);
+ priv->interfaces = NULL;
}
static void
@@ -232,63 +527,77 @@ nm_exported_object_init (NMExportedObject *self)
{
NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
- priv->pending_notifies = g_hash_table_new_full (g_str_hash, g_str_equal,
- NULL, destroy_value);
-}
-
-static void
-add_to_string (gpointer key, gpointer value, gpointer user_data)
-{
- const char *name = (const char *) key;
- GString *buf = user_data;
- GValue str_val = G_VALUE_INIT;
-
- g_value_init (&str_val, G_TYPE_STRING);
- if (!g_value_transform ((GValue *) value, &str_val)) {
- if (G_VALUE_HOLDS_OBJECT (value)) {
- GObject *obj = g_value_get_object (value);
-
- if (obj) {
- g_string_append_printf (buf, "{%s: %p (%s)}, ", name, obj,
- G_OBJECT_TYPE_NAME (obj));
- } else
- g_string_append_printf (buf, "{%s: %p}, ", name, obj);
- } else
- g_string_append_printf (buf, "{%s: <transform error>}, ", name);
- } else
- g_string_append_printf (buf, "{%s: %s}, ", name, g_value_get_string (&str_val));
- g_value_unset (&str_val);
+ g_variant_builder_init (&priv->pending_notifies, G_VARIANT_TYPE_VARDICT);
}
static gboolean
idle_emit_properties_changed (gpointer self)
{
NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
+ GVariant *notifies;
+ GSList *iter;
+ GDBusObjectSkeleton *interface = NULL;
+ guint signal_id = 0;
priv->notify_idle_id = 0;
+ notifies = g_variant_builder_end (&priv->pending_notifies);
+ g_variant_ref_sink (notifies);
+ g_variant_builder_init (&priv->pending_notifies, G_VARIANT_TYPE_VARDICT);
+
+ for (iter = priv->interfaces; iter; iter = iter->next) {
+ signal_id = g_signal_lookup ("properties-changed", G_OBJECT_TYPE (iter->data));
+ if (signal_id != 0) {
+ interface = iter->data;
+ break;
+ }
+ }
+ g_return_val_if_fail (signal_id != 0, FALSE);
if (nm_logging_enabled (LOGL_DEBUG, LOGD_DBUS_PROPS)) {
- GString *buf = g_string_new (NULL);
+ char *notification;
- g_hash_table_foreach (priv->pending_notifies, add_to_string, buf);
- nm_log_dbg (LOGD_DBUS_PROPS, "%s -> %s", G_OBJECT_TYPE_NAME (self), buf->str);
- g_string_free (buf, TRUE);
+ notification = g_variant_print (notifies, TRUE);
+ nm_log_dbg (LOGD_DBUS_PROPS, "PropertiesChanged %s %p: %s",
+ G_OBJECT_TYPE_NAME (self), self, notification);
+ g_free (notification);
}
- g_signal_emit (self, signals[PROPERTIES_CHANGED], 0, priv->pending_notifies);
- g_hash_table_remove_all (priv->pending_notifies);
+ g_signal_emit (interface, signal_id, 0, notifies);
+ g_variant_unref (notifies);
return FALSE;
}
+static const GVariantType *
+find_dbus_property_type (GDBusInterfaceSkeleton *skel,
+ const char *dbus_property_name)
+{
+ GDBusInterfaceInfo *iinfo;
+ int i;
+
+ iinfo = g_dbus_interface_skeleton_get_info (skel);
+ for (i = 0; iinfo->properties[i]; i++) {
+ if (!strcmp (iinfo->properties[i]->name, dbus_property_name))
+ return G_VARIANT_TYPE (iinfo->properties[i]->signature);
+ }
+
+ return NULL;
+}
+
static void
nm_exported_object_notify (GObject *object, GParamSpec *pspec)
{
NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (object);
NMExportedObjectClassInfo *classinfo;
- const char *dbus_property_name = NULL;
- GValue *value;
GType type;
+ const char *dbus_property_name = NULL;
+ GValue value = G_VALUE_INIT;
+ const GVariantType *vtype;
+ GVariant *variant;
+ GSList *iter;
+
+ if (!priv->interfaces)
+ return;
for (type = G_OBJECT_TYPE (object); type; type = g_type_parent (type)) {
classinfo = g_type_get_qdata (type, nm_exported_object_class_info_quark ());
@@ -305,10 +614,19 @@ nm_exported_object_notify (GObject *object, GParamSpec *pspec)
return;
}
- value = g_slice_new0 (GValue);
- g_value_init (value, pspec->value_type);
- g_object_get_property (object, pspec->name, value);
- g_hash_table_insert (priv->pending_notifies, (char *) dbus_property_name, value);
+ g_value_init (&value, pspec->value_type);
+ g_object_get_property (G_OBJECT (object), pspec->name, &value);
+
+ vtype = NULL;
+ for (iter = priv->interfaces; iter && !vtype; iter = iter->next)
+ vtype = find_dbus_property_type (iter->data, dbus_property_name);
+ g_return_if_fail (vtype != NULL);
+
+ variant = g_dbus_gvalue_to_gvariant (&value, vtype);
+ g_variant_builder_add (&priv->pending_notifies, "{sv}",
+ dbus_property_name,
+ variant);
+ g_value_unset (&value);
if (!priv->notify_idle_id)
priv->notify_idle_id = g_idle_add (idle_emit_properties_changed, object);
@@ -322,20 +640,13 @@ nm_exported_object_dispose (GObject *object)
if (priv->path)
nm_exported_object_unexport (NM_EXPORTED_OBJECT (object));
- g_hash_table_remove_all (priv->pending_notifies);
+ g_variant_builder_clear (&priv->pending_notifies);
nm_clear_g_source (&priv->notify_idle_id);
- G_OBJECT_CLASS (nm_exported_object_parent_class)->dispose (object);
-}
+ g_slist_free_full (priv->interfaces, g_object_unref);
+ priv->interfaces = NULL;
-static void
-nm_exported_object_finalize (GObject *object)
-{
- NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (object);
-
- g_hash_table_destroy (priv->pending_notifies);
-
- G_OBJECT_CLASS (nm_exported_object_parent_class)->finalize (object);
+ G_OBJECT_CLASS (nm_exported_object_parent_class)->dispose (object);
}
static void
@@ -345,14 +656,6 @@ nm_exported_object_class_init (NMExportedObjectClass *klass)
g_type_class_add_private (object_class, sizeof (NMExportedObjectPrivate));
- object_class->notify = nm_exported_object_notify;
+ object_class->notify = nm_exported_object_notify;
object_class->dispose = nm_exported_object_dispose;
- object_class->finalize = nm_exported_object_finalize;
-
- signals[PROPERTIES_CHANGED] = g_signal_new ("properties-changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL,
- G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT);
-
}
diff --git a/src/nm-exported-object.h b/src/nm-exported-object.h
index e0ffd9e06b..64e2a5b7a3 100644
--- a/src/nm-exported-object.h
+++ b/src/nm-exported-object.h
@@ -21,9 +21,8 @@
#ifndef NM_EXPORTED_OBJECT_H
#define NM_EXPORTED_OBJECT_H
-#include <dbus/dbus-glib.h>
-
#include "nm-default.h"
+#include "nm-types.h"
G_BEGIN_DECLS
@@ -47,7 +46,8 @@ typedef struct {
GType nm_exported_object_get_type (void);
void nm_exported_object_class_add_interface (NMExportedObjectClass *object_class,
- const DBusGObjectInfo *info);
+ GType dbus_skeleton_type,
+ ...) G_GNUC_NULL_TERMINATED;
const char *nm_exported_object_export (NMExportedObject *self);
const char *nm_exported_object_get_path (NMExportedObject *self);