GDBus: Catch up with new PropertiesChanged signal

After a long discussion, this has finally been standardized in the
D-Bus spec. See

 http://lists.freedesktop.org/archives/dbus/2010-May/012667.html
 http://lists.freedesktop.org/archives/dbus/2010-May/012712.html

Signed-off-by: David Zeuthen <davidz@redhat.com>
This commit is contained in:
David Zeuthen 2010-05-13 11:56:15 -04:00
parent 2d75583fb2
commit 82158afdad
9 changed files with 136 additions and 62 deletions

View File

@ -3549,6 +3549,7 @@ static const gchar introspect_standard_interfaces[] =
" <signal name=\"PropertiesChanged\">\n"
" <arg type=\"s\" name=\"interface_name\"/>\n"
" <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"
" <arg type=\"as\" name=\"invalidated_properties\"/>\n"
" </signal>\n"
" </interface>\n"
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"

View File

@ -387,10 +387,17 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
/**
* GDBusProxy::g-properties-changed:
* @proxy: The #GDBusProxy emitting the signal.
* @changed_properties: A #GVariant containing the properties that changed.
* @changed_properties: A #GVariant containing the properties that
* changed or %NULL if no properties changed.
* @invalidated_properties: A %NULL terminated list of properties that was
* invalidated or %NULL if no properties was invalidated.
*
* Emitted when one or more D-Bus properties on @proxy changes. The cached properties
* are already replaced when this signal fires.
* Emitted when one or more D-Bus properties on @proxy changes. The
* local cache has already been updated when this signal fires.
*
* This signal corresponds to the
* <literal>PropertiesChanged</literal> D-Bus signal on the
* <literal>org.freedesktop.DBus.Properties</literal> interface.
*
* Since: 2.26
*/
@ -400,10 +407,11 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
G_STRUCT_OFFSET (GDBusProxyClass, g_properties_changed),
NULL,
NULL,
g_cclosure_marshal_VOID__BOXED,
_gio_marshal_VOID__BOXED_BOXED,
G_TYPE_NONE,
1,
G_TYPE_VARIANT);
2,
G_TYPE_VARIANT,
G_TYPE_STRV);
/**
* GDBusProxy::g-signal:
@ -669,12 +677,17 @@ on_properties_changed (GDBusConnection *connection,
GError *error;
const gchar *interface_name_for_signal;
GVariantIter *iter;
GVariantIter *invalidated_iter;
GVariant *item;
GVariant *changed_properties;
GVariantBuilder *builder;
GPtrArray *p;
const gchar *str;
gchar **invalidated_properties;
error = NULL;
iter = NULL;
invalidated_iter = NULL;
#if 0 // TODO!
/* Ignore this signal if properties are not yet available
@ -686,27 +699,31 @@ on_properties_changed (GDBusConnection *connection,
goto out;
#endif
if (strcmp (g_variant_get_type_string (parameters), "(sa{sv})") != 0)
if (strcmp (g_variant_get_type_string (parameters), "(sa{sv}as)") != 0)
{
g_warning ("Value for PropertiesChanged signal with type `%s' does not match `(sa{sv})'",
g_warning ("Value for PropertiesChanged signal with type `%s' does not match `(sa{sv}as)'",
g_variant_get_type_string (parameters));
goto out;
}
g_variant_get (parameters,
"(sa{sv})",
"(sa{sv}as)",
&interface_name_for_signal,
&iter);
&iter,
&invalidated_iter);
if (g_strcmp0 (interface_name_for_signal, proxy->priv->interface_name) != 0)
goto out;
builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
builder = NULL;
while ((item = g_variant_iter_next_value (iter)))
{
const gchar *key;
GVariant *value;
if (builder == NULL)
builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
g_variant_get (item,
"{sv}",
&key,
@ -721,16 +738,45 @@ on_properties_changed (GDBusConnection *connection,
g_strdup (key),
g_variant_ref (value));
}
changed_properties = g_variant_builder_end (builder);
if (builder != NULL)
changed_properties = g_variant_builder_end (builder);
else
changed_properties = NULL;
p = NULL;
while (g_variant_iter_loop (invalidated_iter, "s", &str))
{
if (p == NULL)
p = g_ptr_array_new ();
g_ptr_array_add (p, (gpointer) str);
}
if (p != NULL)
{
g_ptr_array_add (p, NULL);
invalidated_properties = (gchar **) g_ptr_array_free (p, FALSE);
}
else
{
invalidated_properties = NULL;
}
/* emit signal */
g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL], 0, changed_properties);
g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
0,
changed_properties,
invalidated_properties);
g_variant_unref (changed_properties);
if (changed_properties != NULL)
g_variant_unref (changed_properties);
if (invalidated_properties != NULL)
g_free (invalidated_properties);
out:
if (iter != NULL)
g_variant_iter_free (iter);
if (invalidated_iter != NULL)
g_variant_iter_free (invalidated_iter);
}
/* ---------------------------------------------------------------------------------------------------- */

View File

@ -69,12 +69,13 @@ struct _GDBusProxyClass
/*< public >*/
/* Signals */
void (*g_properties_changed) (GDBusProxy *proxy,
GVariant *changed_properties);
void (*g_signal) (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters);
void (*g_properties_changed) (GDBusProxy *proxy,
GVariant *changed_properties,
const gchar* const *invalidated_properties);
void (*g_signal) (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters);
/*< private >*/
/* Padding for future expansion */

View File

@ -8,3 +8,4 @@ BOOL:POINTER,INT
BOOL:UINT
VOID:STRING,STRING,BOXED
VOID:BOOL,BOXED
VOID:BOXED,BOXED

View File

@ -233,9 +233,11 @@ send_property_change (GObject *obj,
GDBusConnection *connection)
{
GVariantBuilder *builder;
GVariantBuilder *invalidated_builder;
MyObject *myobj = (MyObject *)obj;
builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
if (g_strcmp0 (pspec->name, "count") == 0)
g_variant_builder_add (builder,
@ -251,9 +253,10 @@ send_property_change (GObject *obj,
"/org/myorg/MyObject",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
g_variant_new ("(sa{sv})",
g_variant_new ("(sa{sv}as)",
"org.myorg.MyObject",
builder),
builder,
invalidated_builder),
NULL);
}

View File

@ -202,27 +202,31 @@ accounts_user_g_signal (GDBusProxy *proxy,
}
static void
accounts_user_g_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties)
accounts_user_g_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
const gchar* const *invalidated_properties)
{
AccountsUser *user = ACCOUNTS_USER (proxy);
GVariantIter *iter;
GVariant *item;
g_variant_get (changed_properties, "a{sv}", &iter);
while ((item = g_variant_iter_next_value (iter)) != NULL)
if (changed_properties != NULL)
{
const gchar *key;
g_variant_get (item,
"{sv}",
&key,
NULL);
if (g_strcmp0 (key, "AutomaticLogin") == 0)
g_object_notify (G_OBJECT (user), "automatic-login");
else if (g_strcmp0 (key, "RealName") == 0)
g_object_notify (G_OBJECT (user), "real-name");
else if (g_strcmp0 (key, "UserName") == 0)
g_object_notify (G_OBJECT (user), "user-name");
g_variant_get (changed_properties, "a{sv}", &iter);
while ((item = g_variant_iter_next_value (iter)) != NULL)
{
const gchar *key;
g_variant_get (item,
"{sv}",
&key,
NULL);
if (g_strcmp0 (key, "AutomaticLogin") == 0)
g_object_notify (G_OBJECT (user), "automatic-login");
else if (g_strcmp0 (key, "RealName") == 0)
g_object_notify (G_OBJECT (user), "real-name");
else if (g_strcmp0 (key, "UserName") == 0)
g_object_notify (G_OBJECT (user), "user-name");
}
}
}

View File

@ -243,9 +243,10 @@ handle_set_property (GDBusConnection *connection,
object_path,
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
g_variant_new ("(sa{sv})",
g_variant_new ("(sa{sv}as)",
interface_name,
builder),
builder,
NULL),
&local_error);
g_assert_no_error (local_error);
}
@ -283,12 +284,14 @@ on_timeout_cb (gpointer user_data)
{
GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
GVariantBuilder *builder;
GVariantBuilder *invalidated_builder;
GError *error;
swap_a_and_b = !swap_a_and_b;
error = NULL;
builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
g_variant_builder_add (builder,
"{sv}",
"Foo",
@ -302,9 +305,10 @@ on_timeout_cb (gpointer user_data)
"/org/gtk/GDBus/TestObject",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
g_variant_new ("(sa{sv})",
g_variant_new ("(sa{sv}as)",
"org.gtk.GDBus.TestInterface",
builder),
builder,
invalidated_builder),
&error);
g_assert_no_error (error);

View File

@ -42,32 +42,45 @@ print_properties (GDBusProxy *proxy)
}
static void
on_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
gpointer user_data)
on_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
const gchar* const *invalidated_properties,
gpointer user_data)
{
GVariantIter *iter;
GVariant *item;
g_print (" *** Properties Changed:\n");
g_variant_get (changed_properties,
"a{sv}",
&iter);
while ((item = g_variant_iter_next_value (iter)))
if (changed_properties != NULL)
{
const gchar *key;
GVariant *value;
gchar *value_str;
GVariantIter *iter;
GVariant *item;
g_variant_get (item,
"{sv}",
&key,
&value);
g_print (" *** Properties Changed:\n");
g_variant_get (changed_properties,
"a{sv}",
&iter);
while ((item = g_variant_iter_next_value (iter)))
{
const gchar *key;
GVariant *value;
gchar *value_str;
g_variant_get (item,
"{sv}",
&key,
&value);
value_str = g_variant_print (value, TRUE);
g_print (" %s -> %s\n", key, value_str);
g_free (value_str);
}
}
value_str = g_variant_print (value, TRUE);
g_print (" %s -> %s\n", key, value_str);
g_free (value_str);
if (invalidated_properties != NULL)
{
guint n;
g_print (" *** Properties Invalidated:\n");
for (n = 0; invalidated_properties[n] != NULL; n++)
{
const gchar *key = invalidated_properties[n];
g_print (" %s\n", key);
}
}
}

View File

@ -187,6 +187,7 @@ class TestService(dbus.service.Object):
"PropertiesChanged")
message.append("com.example.Frob")
message.append({prop_name : prop_value})
message.append([], signature="as")
session_bus.send_message(message)
# ----------------------------------------------------------------------------------------------------