diff options
author | David Zeuthen <davidz@redhat.com> | 2012-02-08 12:46:04 -0500 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2012-02-08 12:49:22 -0500 |
commit | a067df5d720096a62736d26c9e971363c0843d91 (patch) | |
tree | e6244d508aa6f9e6e2e6a1a064ed39ebf1da3854 | |
parent | 1370804f2b1cbb39875bb6a8a53f5bc5318092f4 (diff) | |
download | glib-a067df5d720096a62736d26c9e971363c0843d91.tar.gz |
GDBusProxy: Add G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES flag
This is useful when using certain D-Bus services where the
PropertiesChanged signal does not include the property value such as
e.g. various systemd mechanisms, see e.g.
https://bugs.freedesktop.org/show_bug.cgi?id=37632
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r-- | gio/gdbusproxy.c | 108 | ||||
-rw-r--r-- | gio/gioenums.h | 4 | ||||
-rw-r--r-- | gio/tests/gdbus-proxy.c | 47 | ||||
-rwxr-xr-x | gio/tests/gdbus-testserver.py | 6 |
4 files changed, 153 insertions, 12 deletions
diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c index 52b222b6d..ee9be8285 100644 --- a/gio/gdbusproxy.c +++ b/gio/gdbusproxy.c @@ -587,6 +587,10 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) * that both @changed_properties and @invalidated_properties are * guaranteed to never be %NULL (either may be empty though). * + * If the proxy has the flag + * %G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES set, then + * @invalidated_properties will always be empty. + * * This signal corresponds to the * <literal>PropertiesChanged</literal> D-Bus signal on the * <literal>org.freedesktop.DBus.Properties</literal> interface. @@ -971,6 +975,63 @@ insert_property_checked (GDBusProxy *proxy, g_free (property_name); } +typedef struct +{ + GDBusProxy *proxy; + gchar *prop_name; +} InvalidatedPropGetData; + +static void +invalidated_property_get_cb (GDBusConnection *connection, + GAsyncResult *res, + gpointer user_data) +{ + InvalidatedPropGetData *data = user_data; + const gchar *invalidated_properties[] = {NULL}; + GVariantBuilder builder; + GVariant *value = NULL; + GVariant *unpacked_value = NULL; + + /* errors are fine, the other end could have disconnected */ + value = g_dbus_connection_call_finish (connection, res, NULL); + if (value == NULL) + { + goto out; + } + + if (!g_variant_is_of_type (value, G_VARIANT_TYPE ("(v)"))) + { + g_warning ("Expected type `(v)' for Get() reply, got `%s'", g_variant_get_type_string (value)); + goto out; + } + + g_variant_get (value, "(v)", &unpacked_value); + + /* synthesize the a{sv} in the PropertiesChanged signal */ + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", data->prop_name, unpacked_value); + + G_LOCK (properties_lock); + insert_property_checked (data->proxy, + data->prop_name, /* adopts string */ + unpacked_value); /* adopts value */ + data->prop_name = NULL; + G_UNLOCK (properties_lock); + + g_signal_emit (data->proxy, + signals[PROPERTIES_CHANGED_SIGNAL], 0, + g_variant_builder_end (&builder), /* consumed */ + invalidated_properties); + + + out: + if (value != NULL) + g_variant_unref (value); + g_object_unref (data->proxy); + g_free (data->prop_name); + g_slice_free (InvalidatedPropGetData, data); +} + static void on_properties_changed (GDBusConnection *connection, const gchar *sender_name, @@ -981,6 +1042,7 @@ on_properties_changed (GDBusConnection *connection, gpointer user_data) { SignalSubscriptionData *data = user_data; + gboolean emit_g_signal = FALSE; GDBusProxy *proxy; const gchar *interface_name_for_signal; GVariant *changed_properties; @@ -1043,20 +1105,52 @@ on_properties_changed (GDBusConnection *connection, insert_property_checked (proxy, key, /* adopts string */ value); /* adopts value */ + emit_g_signal = TRUE; } - for (n = 0; invalidated_properties[n] != NULL; n++) + if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES) + { + if (proxy->priv->name_owner != NULL) + { + for (n = 0; invalidated_properties[n] != NULL; n++) + { + InvalidatedPropGetData *data; + data = g_slice_new0 (InvalidatedPropGetData); + data->proxy = g_object_ref (proxy); + data->prop_name = g_strdup (invalidated_properties[n]); + g_dbus_connection_call (proxy->priv->connection, + proxy->priv->name_owner, + proxy->priv->object_path, + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", proxy->priv->interface_name, data->prop_name), + G_VARIANT_TYPE ("(v)"), + G_DBUS_CALL_FLAGS_NONE, + -1, /* timeout */ + NULL, /* GCancellable */ + (GAsyncReadyCallback) invalidated_property_get_cb, + data); + } + } + } + else { - g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]); + emit_g_signal = TRUE; + for (n = 0; invalidated_properties[n] != NULL; n++) + { + g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]); + } } G_UNLOCK (properties_lock); - /* emit signal */ - g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL], - 0, - changed_properties, - invalidated_properties); + if (emit_g_signal) + { + g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL], + 0, + changed_properties, + invalidated_properties); + } out: if (changed_properties != NULL) diff --git a/gio/gioenums.h b/gio/gioenums.h index d1fadf1f0..b2b786128 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -880,6 +880,7 @@ typedef enum * @G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START: If not set and the proxy if for a well-known name, * then request the bus to launch an owner for the name if no-one owns the name. This flag can * only be used in proxies for well-known names. + * @G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES: If set, the property value for any <emphasis>invalidated property</emphasis> will be (asynchronously) retrieved upon receiving the <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties">PropertiesChanged</ulink> D-Bus signal and the property will not cause emission of the #GDBusProxy::g-properties-changed signal. When the value is received the #GDBusProxy::g-properties-changed signal is emitted for the property along with the retrieved value. Since 2.32. * * Flags used when constructing an instance of a #GDBusProxy derived class. * @@ -890,7 +891,8 @@ typedef enum G_DBUS_PROXY_FLAGS_NONE = 0, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0), G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1), - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2) + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2), + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES = (1<<3) } GDBusProxyFlags; /** diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c index 0b2905ca9..00e627407 100644 --- a/gio/tests/gdbus-proxy.c +++ b/gio/tests/gdbus-proxy.c @@ -280,7 +280,7 @@ test_properties (GDBusProxy *proxy) */ result = g_dbus_proxy_call_sync (proxy, "FrobInvalidateProperty", - NULL, + g_variant_new ("(s)", "OMGInvalidated"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, @@ -294,6 +294,51 @@ test_properties (GDBusProxy *proxy) /* ... and now we finally, check that the cached value has been invalidated */ variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated"); g_assert (variant == NULL); + + /* Now test that G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES works - we need a new proxy for that */ + gchar *name_owner; + GDBusProxy *proxy2; + error = NULL; + proxy2 = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy), + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + NULL, /* GDBusInterfaceInfo */ + "com.example.TestService", /* name */ + "/com/example/TestObject", /* object path */ + "com.example.Frob", /* interface */ + NULL, /* GCancellable */ + &error); + g_assert_no_error (error); + + name_owner = g_dbus_proxy_get_name_owner (proxy2); + g_assert (name_owner != NULL); + g_free (name_owner); + + variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated"); + g_assert (variant != NULL); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated"); /* from previous test */ + g_variant_unref (variant); + + result = g_dbus_proxy_call_sync (proxy2, + "FrobInvalidateProperty", + g_variant_new ("(s)", "OMGInvalidated2"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + g_assert_no_error (error); + g_assert (result != NULL); + g_assert_cmpstr (g_variant_get_type_string (result), ==, "()"); + g_variant_unref (result); + + /* this time we should get the ::g-properties-changed _with_ the value */ + _g_assert_signal_received (proxy2, "g-properties-changed"); + + variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated"); + g_assert (variant != NULL); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated2"); + g_variant_unref (variant); + + g_object_unref (proxy2); } /* ---------------------------------------------------------------------------------------------------- */ diff --git a/gio/tests/gdbus-testserver.py b/gio/tests/gdbus-testserver.py index 6b2b64bdc..645a7e443 100755 --- a/gio/tests/gdbus-testserver.py +++ b/gio/tests/gdbus-testserver.py @@ -193,9 +193,9 @@ class TestService(dbus.service.Object): # ---------------------------------------------------------------------------------------------------- @dbus.service.method("com.example.Frob", - in_signature='', out_signature='') - def FrobInvalidateProperty(self): - self.frob_props["PropertyThatWillBeInvalidated"] = "OMGInvalidated" + in_signature='s', out_signature='') + def FrobInvalidateProperty(self, new_value): + self.frob_props["PropertyThatWillBeInvalidated"] = new_value message = dbus.lowlevel.SignalMessage("/com/example/TestObject", "org.freedesktop.DBus.Properties", "PropertiesChanged") |