This splits the core of bus_map_all_properties() out into a new helper
called bus_message_map_all_properties(). Instead of sending a blocking
dbus call, this helper takes the response message as argument and parses
it. So the normal use-case is to send an async GetAll() request and once
you get the response, pass it to the helper to map the properties.
The existing bus_map_all_properties() helper is now just a small wrapper
around sd_bus_call_method() and the new helper.
Furthermore, a second helper is added which parses PropertiesChanged
dbus signals. Whenever you get such a signal, you can pass the message to
a new helper called bus_message_map_properties_changed(). It parses the
PropertiesChanged payload for changed properties and maps them. In case
the payload only contains invalidation-requests and no new values, this
functions returns the number of successfully mapped properties that were
invalidated. Thus, if it returns 0, you should send a GetAll() or Get()
request.
Both helpers allow very convenient handling of dbus-properties in a
non-blocking fashion. This is required for graphics-applications and other
programs that need low-latency responses. In all other cases, the existing
blocking bus_map_all_properties() helper should be enough.
---
src/libsystemd-bus/bus-util.c | 87 ++-
src/libsystemd-bus/bus-util.h | 6 +++
2 files changed, 68 insertions(+), 25 deletions(-)
diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c
index 2daf8c1..0e520c1 100644
--- a/src/libsystemd-bus/bus-util.c
+++ b/src/libsystemd-bus/bus-util.c
@@ -838,31 +838,12 @@ static int map_basic(sd_bus *bus, const char *member,
sd_bus_message *m, sd_bus_
return r;
}
-int bus_map_all_properties(sd_bus *bus,
- const char *destination,
- const char *path,
- const struct bus_properties_map *map,
- void *userdata) {
-_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+int bus_message_map_all_properties(sd_bus_message *m,
+ const struct bus_properties_map *map,
+ void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
-assert(bus);
-assert(destination);
-assert(path);
-assert(map);
-
-r = sd_bus_call_method( bus,
-destination,
-path,
-org.freedesktop.DBus.Properties,
-GetAll,
-error,
-m,
-s, );
-if (r 0)
-return r;
-
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, {sv});
if (r 0)
return r;
@@ -895,9 +876,9 @@ int bus_map_all_properties(sd_bus *bus,
v = (uint8_t *)userdata + prop-offset;
if (map[i].set)
-r = prop-set(bus, member, m, error, v);
+r = prop-set(m-bus, member, m, error, v);
else
-r = map_basic(bus, member, m, error, v);
+r = map_basic(m-bus, member, m, error, v);
r = sd_bus_message_exit_container(m);
if (r 0)
@@ -913,7 +894,63 @@ int bus_map_all_properties(sd_bus *bus,
return r;
}
-return r;
+return sd_bus_message_exit_container(m);
+}
+
+int bus_map_all_properties(sd_bus *bus,
+ const char *destination,
+ const char *path,
+ const struct bus_properties_map *map,
+ void *userdata) {
+_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+int r;
+
+assert(bus);
+assert(destination);
+assert(path);
+assert(map);
+
+r = sd_bus_call_method( bus,
+destination,
+path,
+org.freedesktop.DBus.Properties,
+GetAll,
+error,
+m,
+s, );
+if (r 0)
+return r;
+
+return bus_message_map_all_properties(m, map, userdata);
+}
+
+int bus_message_map_properties_changed(sd_bus_message *m,
+ const struct bus_properties_map *map,
+ void *userdata) {
+const char *member;
+int r, invalidated, i;
+
+/* skip interface, but allow callers to do that themselves */
+sd_bus_message_skip(m, s);
+
+r =