mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-20 07:38:54 +02:00
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>
This commit is contained in:
108
gio/gdbusproxy.c
108
gio/gdbusproxy.c
@@ -587,6 +587,10 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
|
|||||||
* that both @changed_properties and @invalidated_properties are
|
* that both @changed_properties and @invalidated_properties are
|
||||||
* guaranteed to never be %NULL (either may be empty though).
|
* 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
|
* This signal corresponds to the
|
||||||
* <literal>PropertiesChanged</literal> D-Bus signal on the
|
* <literal>PropertiesChanged</literal> D-Bus signal on the
|
||||||
* <literal>org.freedesktop.DBus.Properties</literal> interface.
|
* <literal>org.freedesktop.DBus.Properties</literal> interface.
|
||||||
@@ -971,6 +975,63 @@ insert_property_checked (GDBusProxy *proxy,
|
|||||||
g_free (property_name);
|
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
|
static void
|
||||||
on_properties_changed (GDBusConnection *connection,
|
on_properties_changed (GDBusConnection *connection,
|
||||||
const gchar *sender_name,
|
const gchar *sender_name,
|
||||||
@@ -981,6 +1042,7 @@ on_properties_changed (GDBusConnection *connection,
|
|||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
SignalSubscriptionData *data = user_data;
|
SignalSubscriptionData *data = user_data;
|
||||||
|
gboolean emit_g_signal = FALSE;
|
||||||
GDBusProxy *proxy;
|
GDBusProxy *proxy;
|
||||||
const gchar *interface_name_for_signal;
|
const gchar *interface_name_for_signal;
|
||||||
GVariant *changed_properties;
|
GVariant *changed_properties;
|
||||||
@@ -1043,20 +1105,52 @@ on_properties_changed (GDBusConnection *connection,
|
|||||||
insert_property_checked (proxy,
|
insert_property_checked (proxy,
|
||||||
key, /* adopts string */
|
key, /* adopts string */
|
||||||
value); /* adopts value */
|
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)
|
||||||
{
|
{
|
||||||
g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]);
|
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
|
||||||
|
{
|
||||||
|
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);
|
G_UNLOCK (properties_lock);
|
||||||
|
|
||||||
/* emit signal */
|
if (emit_g_signal)
|
||||||
g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
|
{
|
||||||
0,
|
g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
|
||||||
changed_properties,
|
0,
|
||||||
invalidated_properties);
|
changed_properties,
|
||||||
|
invalidated_properties);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (changed_properties != NULL)
|
if (changed_properties != NULL)
|
||||||
|
@@ -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,
|
* @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
|
* 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.
|
* 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.
|
* 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_NONE = 0,
|
||||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<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_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;
|
} GDBusProxyFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -280,7 +280,7 @@ test_properties (GDBusProxy *proxy)
|
|||||||
*/
|
*/
|
||||||
result = g_dbus_proxy_call_sync (proxy,
|
result = g_dbus_proxy_call_sync (proxy,
|
||||||
"FrobInvalidateProperty",
|
"FrobInvalidateProperty",
|
||||||
NULL,
|
g_variant_new ("(s)", "OMGInvalidated"),
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
-1,
|
-1,
|
||||||
NULL,
|
NULL,
|
||||||
@@ -294,6 +294,51 @@ test_properties (GDBusProxy *proxy)
|
|||||||
/* ... and now we finally, check that the cached value has been invalidated */
|
/* ... and now we finally, check that the cached value has been invalidated */
|
||||||
variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
|
variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
|
||||||
g_assert (variant == NULL);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
@@ -193,9 +193,9 @@ class TestService(dbus.service.Object):
|
|||||||
# ----------------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@dbus.service.method("com.example.Frob",
|
@dbus.service.method("com.example.Frob",
|
||||||
in_signature='', out_signature='')
|
in_signature='s', out_signature='')
|
||||||
def FrobInvalidateProperty(self):
|
def FrobInvalidateProperty(self, new_value):
|
||||||
self.frob_props["PropertyThatWillBeInvalidated"] = "OMGInvalidated"
|
self.frob_props["PropertyThatWillBeInvalidated"] = new_value
|
||||||
message = dbus.lowlevel.SignalMessage("/com/example/TestObject",
|
message = dbus.lowlevel.SignalMessage("/com/example/TestObject",
|
||||||
"org.freedesktop.DBus.Properties",
|
"org.freedesktop.DBus.Properties",
|
||||||
"PropertiesChanged")
|
"PropertiesChanged")
|
||||||
|
Reference in New Issue
Block a user