mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-14 20:18:39 +00:00
core: merge branch 'th/dbus-property-changed-source-iface-bgo770629'
https://bugzilla.gnome.org/show_bug.cgi?id=770629
This commit is contained in:
commit
d2550cef44
|
@ -38,14 +38,13 @@ G_DEFINE_ABSTRACT_TYPE (NMExportedObject, nm_exported_object, G_TYPE_DBUS_OBJECT
|
|||
typedef struct {
|
||||
GDBusInterfaceSkeleton *interface;
|
||||
guint property_changed_signal_id;
|
||||
GHashTable *pending_notifies;
|
||||
} InterfaceData;
|
||||
|
||||
typedef struct {
|
||||
NMBusManager *bus_mgr;
|
||||
char *path;
|
||||
|
||||
GHashTable *pending_notifies;
|
||||
|
||||
InterfaceData *interfaces;
|
||||
guint num_interfaces;
|
||||
|
||||
|
@ -268,8 +267,8 @@ nm_exported_object_class_add_interface (NMExportedObjectClass *object_class,
|
|||
nm_exported_object_class_info_quark (), classinfo);
|
||||
}
|
||||
|
||||
classinfo->skeleton_types = g_slist_prepend (classinfo->skeleton_types,
|
||||
GSIZE_TO_POINTER (dbus_skeleton_type));
|
||||
classinfo->skeleton_types = g_slist_append (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.
|
||||
|
@ -492,6 +491,11 @@ nm_exported_object_create_skeletons (NMExportedObject *self,
|
|||
g_dbus_object_skeleton_add_interface ((GDBusObjectSkeleton *) self, ifdata->interface);
|
||||
|
||||
ifdata->property_changed_signal_id = g_signal_lookup ("properties-changed", G_OBJECT_TYPE (ifdata->interface));
|
||||
|
||||
ifdata->pending_notifies = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) g_variant_unref);
|
||||
}
|
||||
nm_assert (i == 0);
|
||||
|
||||
|
@ -542,6 +546,7 @@ nm_exported_object_destroy_skeletons (NMExportedObject *self)
|
|||
|
||||
g_dbus_object_skeleton_remove_interface ((GDBusObjectSkeleton *) self, ifdata->interface);
|
||||
nm_exported_object_skeleton_release (ifdata->interface);
|
||||
g_hash_table_destroy (ifdata->pending_notifies);
|
||||
}
|
||||
|
||||
g_slice_free1 (sizeof (InterfaceData) * n, priv->interfaces);
|
||||
|
@ -701,11 +706,7 @@ nm_exported_object_unexport (NMExportedObject *self)
|
|||
|
||||
g_clear_pointer (&priv->path, g_free);
|
||||
|
||||
if (nm_clear_g_source (&priv->notify_idle_id)) {
|
||||
/* We had a notification queued. Since we removed all interfaces,
|
||||
* the notification is obsolete and must be cleaned up. */
|
||||
g_hash_table_remove_all (priv->pending_notifies);
|
||||
}
|
||||
nm_clear_g_source (&priv->notify_idle_id);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -784,53 +785,60 @@ static gboolean
|
|||
idle_emit_properties_changed (gpointer self)
|
||||
{
|
||||
NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
|
||||
gs_unref_variant GVariant *variant = NULL;
|
||||
InterfaceData *ifdata = NULL;
|
||||
GHashTableIter hash_iter;
|
||||
GVariantBuilder notifies;
|
||||
guint i, n;
|
||||
PendingNotifiesItem *values;
|
||||
guint k;
|
||||
|
||||
priv->notify_idle_id = 0;
|
||||
|
||||
for (k = 0; k < priv->num_interfaces; k++) {
|
||||
InterfaceData *ifdata = &priv->interfaces[k];
|
||||
gs_unref_variant GVariant *variant = NULL;
|
||||
PendingNotifiesItem *values;
|
||||
GVariantBuilder notifies;
|
||||
GHashTableIter hash_iter;
|
||||
guint i, n;
|
||||
|
||||
n = g_hash_table_size (priv->pending_notifies);
|
||||
g_return_val_if_fail (n > 0, FALSE);
|
||||
n = g_hash_table_size (ifdata->pending_notifies);
|
||||
if (n == 0)
|
||||
continue;
|
||||
|
||||
values = g_alloca (sizeof (values[0]) * n);
|
||||
if (!ifdata->property_changed_signal_id)
|
||||
goto next;
|
||||
|
||||
i = 0;
|
||||
g_hash_table_iter_init (&hash_iter, priv->pending_notifies);
|
||||
while (g_hash_table_iter_next (&hash_iter, (gpointer) &values[i].property_name, (gpointer) &values[i].variant))
|
||||
i++;
|
||||
nm_assert (i == n);
|
||||
/* We use here alloca in a loop, something that is usually avoided.
|
||||
* But the number of interfaces "priv->num_interfaces" is small (determined by
|
||||
* the depth of the type inheritence) and the number of possible pending_notifies
|
||||
* "n" is small (determined by the number of GObject properties). */
|
||||
values = g_alloca (sizeof (values[0]) * n);
|
||||
|
||||
g_qsort_with_data (values, n, sizeof (values[0]), _sort_pending_notifies, NULL);
|
||||
i = 0;
|
||||
g_hash_table_iter_init (&hash_iter, ifdata->pending_notifies);
|
||||
while (g_hash_table_iter_next (&hash_iter, (gpointer) &values[i].property_name, (gpointer) &values[i].variant))
|
||||
i++;
|
||||
nm_assert (i == n);
|
||||
|
||||
g_variant_builder_init (¬ifies, G_VARIANT_TYPE_VARDICT);
|
||||
for (i = 0; i < n; i++)
|
||||
g_variant_builder_add (¬ifies, "{sv}", values[i].property_name, values[i].variant);
|
||||
variant = g_variant_ref_sink (g_variant_builder_end (¬ifies));
|
||||
g_qsort_with_data (values, n, sizeof (values[0]), _sort_pending_notifies, NULL);
|
||||
|
||||
g_hash_table_remove_all (priv->pending_notifies);
|
||||
g_variant_builder_init (¬ifies, G_VARIANT_TYPE_VARDICT);
|
||||
for (i = 0; i < n; i++)
|
||||
g_variant_builder_add (¬ifies, "{sv}", values[i].property_name, values[i].variant);
|
||||
variant = g_variant_ref_sink (g_variant_builder_end (¬ifies));
|
||||
|
||||
for (i = 0; i < priv->num_interfaces; i++) {
|
||||
if (priv->interfaces[i].property_changed_signal_id != 0) {
|
||||
ifdata = &priv->interfaces[i];
|
||||
break;
|
||||
|
||||
if (nm_logging_enabled (LOGL_DEBUG, LOGD_DBUS_PROPS)) {
|
||||
gs_free char *notification = g_variant_print (variant, TRUE);
|
||||
|
||||
nm_log_dbg (LOGD_DBUS_PROPS, "properties-changed[%p]: type %s, iface %s: %s",
|
||||
self, G_OBJECT_TYPE_NAME (self), G_OBJECT_TYPE_NAME (ifdata->interface),
|
||||
notification);
|
||||
}
|
||||
}
|
||||
g_return_val_if_fail (ifdata, FALSE);
|
||||
|
||||
if (nm_logging_enabled (LOGL_DEBUG, LOGD_DBUS_PROPS)) {
|
||||
gs_free char *notification = g_variant_print (variant, TRUE);
|
||||
g_signal_emit (ifdata->interface, ifdata->property_changed_signal_id, 0, variant);
|
||||
|
||||
nm_log_dbg (LOGD_DBUS_PROPS, "PropertiesChanged %s %p: %s",
|
||||
G_OBJECT_TYPE_NAME (self), self, notification);
|
||||
next:
|
||||
g_hash_table_remove_all (ifdata->pending_notifies);
|
||||
}
|
||||
|
||||
g_signal_emit (ifdata->interface, ifdata->property_changed_signal_id, 0, variant);
|
||||
return FALSE;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -841,6 +849,7 @@ nm_exported_object_notify (GObject *object, GParamSpec *pspec)
|
|||
GType type;
|
||||
const char *dbus_property_name = NULL;
|
||||
GValue value = G_VALUE_INIT;
|
||||
InterfaceData *ifdata = NULL;
|
||||
const GVariantType *vtype;
|
||||
guint i, j;
|
||||
|
||||
|
@ -857,16 +866,16 @@ nm_exported_object_notify (GObject *object, GParamSpec *pspec)
|
|||
break;
|
||||
}
|
||||
if (!dbus_property_name) {
|
||||
nm_log_trace (LOGD_DBUS_PROPS, "ignoring notification for prop %s on type %s",
|
||||
pspec->name, G_OBJECT_TYPE_NAME (object));
|
||||
nm_log_trace (LOGD_DBUS_PROPS, "properties-changed[%p]: ignoring notification for prop %s on type %s",
|
||||
object, pspec->name, G_OBJECT_TYPE_NAME (object));
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->num_interfaces; i++) {
|
||||
GDBusInterfaceSkeleton *skel = priv->interfaces[i].interface;
|
||||
GDBusInterfaceInfo *iinfo;
|
||||
|
||||
iinfo = g_dbus_interface_skeleton_get_info (skel);
|
||||
ifdata = &priv->interfaces[i];
|
||||
iinfo = g_dbus_interface_skeleton_get_info (ifdata->interface);
|
||||
for (j = 0; iinfo->properties[j]; j++) {
|
||||
if (nm_streq (iinfo->properties[j]->name, dbus_property_name)) {
|
||||
vtype = G_VARIANT_TYPE (iinfo->properties[j]->signature);
|
||||
|
@ -882,7 +891,7 @@ vtype_found:
|
|||
|
||||
/* @dbus_property_name is inside classinfo and never freed, thus we don't clone it.
|
||||
* Also, we do a pointer, not string comparison. */
|
||||
g_hash_table_insert (priv->pending_notifies,
|
||||
g_hash_table_insert (ifdata->pending_notifies,
|
||||
(gpointer) dbus_property_name,
|
||||
g_dbus_gvalue_to_gvariant (&value, vtype));
|
||||
g_value_unset (&value);
|
||||
|
@ -896,12 +905,6 @@ vtype_found:
|
|||
static void
|
||||
nm_exported_object_init (NMExportedObject *self)
|
||||
{
|
||||
NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
|
||||
|
||||
priv->pending_notifies = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) g_variant_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -937,7 +940,6 @@ nm_exported_object_dispose (GObject *object)
|
|||
} else
|
||||
g_clear_pointer (&priv->path, g_free);
|
||||
|
||||
g_clear_pointer (&priv->pending_notifies, g_hash_table_destroy);
|
||||
nm_clear_g_source (&priv->notify_idle_id);
|
||||
|
||||
G_OBJECT_CLASS (nm_exported_object_parent_class)->dispose (object);
|
||||
|
|
Loading…
Reference in a new issue