aboutsummaryrefslogtreecommitdiffstats
path: root/gdbus/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdbus/object.c')
-rw-r--r--gdbus/object.c247
1 files changed, 237 insertions, 10 deletions
diff --git a/gdbus/object.c b/gdbus/object.c
index 662ebe3..214968e 100644
--- a/gdbus/object.c
+++ b/gdbus/object.c
@@ -37,10 +37,16 @@
#define error(fmt...)
#define debug(fmt...)
+#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
+
struct generic_data {
unsigned int refcount;
+ DBusConnection *conn;
+ char *path;
GSList *interfaces;
+ GSList *objects;
char *introspect;
+ struct generic_data *parent;
};
struct interface_data {
@@ -477,11 +483,28 @@ void g_dbus_pending_property_error(DBusConnection *connection,
va_end(args);
}
+static void reset_parent(gpointer data, gpointer user_data)
+{
+ struct generic_data *child = data;
+ struct generic_data *parent = user_data;
+
+ child->parent = parent;
+}
+
static void generic_unregister(DBusConnection *connection, void *user_data)
{
struct generic_data *data = user_data;
+ struct generic_data *parent = data->parent;
+ if (parent != NULL)
+ parent->objects = g_slist_remove(parent->objects, data);
+
+ g_slist_foreach(data->objects, reset_parent, data->parent);
+ g_slist_free(data->objects);
+
+ dbus_connection_unref(data->conn);
g_free(data->introspect);
+ g_free(data->path);
g_free(data);
}
@@ -563,9 +586,10 @@ static DBusObjectPathVTable generic_table = {
.message_function = generic_message,
};
-static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
+static struct generic_data *invalidate_parent_data(DBusConnection *conn,
+ const char *child_path)
{
- struct generic_data *data = NULL;
+ struct generic_data *data = NULL, *child = NULL, *parent = NULL;
char *parent_path, *slash;
parent_path = g_strdup(child_path);
@@ -586,16 +610,30 @@ static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
goto done;
}
- invalidate_parent_data(conn, parent_path);
+ parent = invalidate_parent_data(conn, parent_path);
- if (data == NULL)
- goto done;
+ if (data == NULL) {
+ data = parent;
+ if (data == NULL)
+ goto done;
+ }
g_free(data->introspect);
data->introspect = NULL;
+ if (!dbus_connection_get_object_path_data(conn, child_path,
+ (void *) &child))
+ goto done;
+
+ if (child == NULL || g_slist_find(data->objects, child) != NULL)
+ goto done;
+
+ data->objects = g_slist_prepend(data->objects, child);
+ child->parent = data;
+
done:
g_free(parent_path);
+ return data;
}
static const GDBusMethodTable introspect_methods[] = {
@@ -822,7 +860,158 @@ static const GDBusSignalTable properties_signals[] = {
{ }
};
-static void add_interface(struct generic_data *data, const char *name,
+static void append_properties(struct interface_data *data,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ /* TODO: list properties */
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+static void append_interface(gpointer data, gpointer user_data)
+{
+ struct interface_data *iface = data;
+ DBusMessageIter *array = user_data;
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
+ append_properties(data, &entry);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ g_slist_foreach(data->interfaces, append_interface, &array);
+
+ dbus_message_iter_close_container(iter, &array);
+}
+
+static void append_object(gpointer data, gpointer user_data)
+{
+ struct generic_data *child = data;
+ DBusMessageIter *array = user_data;
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+ &child->path);
+ append_interfaces(child, &entry);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+static DBusMessage *get_objects(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct generic_data *data = user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_OBJECT_PATH_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &array);
+
+ g_slist_foreach(data->objects, append_object, &array);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static const GDBusMethodTable manager_methods[] = {
+ { GDBUS_METHOD("GetManagedObjects", NULL,
+ GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
+ { }
+};
+
+static const GDBusSignalTable manager_signals[] = {
+ { GDBUS_SIGNAL("InterfacesAdded",
+ GDBUS_ARGS({ "object", "o" },
+ { "interfaces", "a{sa{sv}}" })) },
+ { GDBUS_SIGNAL("InterfacesRemoved",
+ GDBUS_ARGS({ "object", "o" }, { "interfaces", "as" })) },
+ { }
+};
+
+static void emit_interface_added(struct generic_data *data,
+ struct interface_data *iface)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter, array;
+ struct generic_data *parent = data->parent;
+
+ if (parent == NULL)
+ return;
+
+ signal = dbus_message_new_signal(parent->path,
+ DBUS_INTERFACE_OBJECT_MANAGER,
+ "InterfacesAdded");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &data->path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ append_interface(iface, &array);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ g_dbus_send_message(data->conn, signal);
+}
+
+static void add_interface(struct generic_data *data,
+ const char *name,
const GDBusMethodTable *methods,
const GDBusSignalTable *signals,
const GDBusPropertyTable *properties,
@@ -840,6 +1029,8 @@ static void add_interface(struct generic_data *data, const char *name,
iface->destroy = destroy;
data->interfaces = g_slist_append(data->interfaces, iface);
+
+ emit_interface_added(data, iface);
}
static struct generic_data *object_path_ref(DBusConnection *connection,
@@ -856,6 +1047,8 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
}
data = g_new0(struct generic_data, 1);
+ data->conn = dbus_connection_ref(connection);
+ data->path = g_strdup(path);
data->refcount = 1;
data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
@@ -869,8 +1062,11 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
invalidate_parent_data(connection, path);
- add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
- introspect_methods, NULL, NULL, data, NULL);
+ add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods,
+ NULL, NULL, data, NULL);
+
+ add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER, manager_methods,
+ manager_signals, NULL, data, NULL);
add_interface(data, DBUS_INTERFACE_PROPERTIES, properties_methods,
properties_signals, NULL, data, NULL);
@@ -878,6 +1074,34 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
return data;
}
+static void emit_interface_remove(struct generic_data *data,
+ struct interface_data *iface)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter, array;
+ struct generic_data *parent = data->parent;
+
+ if (parent == NULL)
+ return;
+
+ signal = dbus_message_new_signal(parent->path,
+ DBUS_INTERFACE_OBJECT_MANAGER,
+ "InterfacesRemoved");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &data->path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+ dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &iface->name);
+ dbus_message_iter_close_container(&iter, &array);
+
+ g_dbus_send_message(data->conn, signal);
+}
+
static gboolean remove_interface(struct generic_data *data, const char *name)
{
struct interface_data *iface;
@@ -886,6 +1110,8 @@ static gboolean remove_interface(struct generic_data *data, const char *name)
if (iface == NULL)
return FALSE;
+ emit_interface_remove(data, iface);
+
data->interfaces = g_slist_remove(data->interfaces, iface);
if (iface->destroy)
@@ -915,6 +1141,7 @@ static void object_path_unref(DBusConnection *connection, const char *path)
remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
remove_interface(data, DBUS_INTERFACE_PROPERTIES);
+ remove_interface(data, DBUS_INTERFACE_OBJECT_MANAGER);
invalidate_parent_data(connection, path);
@@ -1013,8 +1240,8 @@ gboolean g_dbus_register_interface(DBusConnection *connection,
return FALSE;
}
- add_interface(data, name, methods, signals,
- properties, user_data, destroy);
+ add_interface(data, name, methods, signals, properties, user_data,
+ destroy);
g_free(data->introspect);
data->introspect = NULL;