summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2009-01-05 00:57:39 -0500
committerRay Strode <rstrode@redhat.com>2009-01-05 01:05:19 -0500
commitd923e259629ee10213d78ded2e5b173084b362e6 (patch)
treed601c9087ba97a31e58058f4bc623f3020cae51a
parentaf9e25c870a69161ff77f961d464da3c771a046b (diff)
Add a mechanism for exporting methods to the bus
This commit adds a lot of the machinery needed to convert from a local function/objecct to one that's remotely invokable. It uses ffi to translate dbus messages to C function calls, and then sends the results from those calls back on the as reply messages. Right now we only export the singleton object /org/freedesktop/Wayland with no methods on it's org.freedesktop.Wayland interface. There is api in place to add methods, though. We'll use this api to add a "GetAddress" method that clients can call to find the server socket. All registered objects get introspection for free. This is accomplished by implicitly attaching the Introspectable interface to the object when it's registered.
-rw-r--r--Makefile.in2
-rw-r--r--dbus.c607
-rw-r--r--wayland-system-compositor.h40
3 files changed, 648 insertions, 1 deletions
diff --git a/Makefile.in b/Makefile.in
index 565ff6b..5d33d92 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -28,6 +28,8 @@ $(libs) :
$(compositors) $(clients) : CFLAGS += @LIBDRM_CFLAGS@
+wayland-system-compositor : CFLAGS += @FFI_CFLAGS@
+wayland-system-compositor : LDLIBS += @FFI_LIBS@ -ldl -rdynamic
wayland-system-compositor : \
wayland-system-compositor.o \
dbus.o \
diff --git a/dbus.c b/dbus.c
index 23d8f31..366c5f5 100644
--- a/dbus.c
+++ b/dbus.c
@@ -17,20 +17,48 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#define _GNU_SOURCE
+#include <pwd.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ffi.h>
#include <dbus/dbus.h>
#include "wayland.h"
#include "wayland-system-compositor.h"
+#define SINGLETON_OBJECT_PATH "/org/freedesktop/Wayland"
+#define SINGLETON_OBJECT_INTERFACE "org.freedesktop.Wayland"
+#define MAX(a, b) ((a) > (b)? (a): (b))
+
+struct wlsc_dbus_interface_ref {
+ struct wlsc_dbus_interface *interface;
+ struct wl_list link;
+};
+
+struct wlsc_dbus_object {
+ char *path;
+ struct wl_list interface_list;
+ uint32_t is_opaque : 1;
+};
+
+struct wlsc_dbus_object_ref {
+ struct wlsc_dbus_object *object;
+ struct wl_list link;
+};
+
struct wlsc_dbus {
DBusConnection *connection;
struct wl_event_loop *loop;
struct wl_event_source *dispatch_source;
+ struct wl_list object_list;
+ struct wlsc_dbus_object *singleton_object;
};
static DBusHandlerResult wlsc_dbus_filter(DBusConnection *connection, DBusMessage *message, void *data)
@@ -45,6 +73,103 @@ static DBusHandlerResult wlsc_dbus_filter(DBusConnection *connection, DBusMessag
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
+#define MAX_METHODS_FOR_SINGLETON 1
+static struct wlsc_dbus_method singleton_object_methods[MAX_METHODS_FOR_SINGLETON] = {
+};
+
+static struct wlsc_dbus_interface singleton_object_interface = {
+ SINGLETON_OBJECT_INTERFACE, 0, singleton_object_methods,
+};
+
+static char *introspect(struct wlsc_dbus_object *object)
+{
+ struct wlsc_dbus_interface_ref *ref;
+ int byte_count;
+ ssize_t buffer_size;
+ char *buffer;
+
+ /* we do a dry run once to compute the size then come back
+ * after allocating the buffer. It's a little groaty. We
+ * could really use a dynamic string api
+ */
+ buffer = NULL;
+ buffer_size = 0;
+fill_buffer:
+ byte_count = 0;
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0), "%s", DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0), "<node>\n");
+ ref = container_of(object->interface_list.next,
+ struct wlsc_dbus_interface_ref, link);
+ while (&ref->link != &object->interface_list) {
+ struct wlsc_dbus_interface *interface;
+ int i;
+
+ interface = ref->interface;
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0),
+ " <interface name=\"%s\">\n",
+ interface->name);
+ for (i = 0; i < interface->method_count; i++) {
+ struct wlsc_dbus_method *method;
+ int j;
+ method = &interface->methods[i];
+
+ if (method->name == buffer + byte_count)
+ continue;
+
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0), " <method name=\"%s\">\n", interface->methods[i].name);
+ for (j = 0; j < method->in_parameter_count; j++) {
+ struct wlsc_dbus_method_parameter *parameter;
+ parameter = &method->in_parameters[j];
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0),
+ " <arg name=\"%s\" direction=\"in\" type=\"%s\"/>\n",
+ parameter->name, parameter->signature);
+ }
+
+ for (j = 0; j < method->out_parameter_count; j++) {
+ struct wlsc_dbus_method_parameter *parameter;
+ parameter = &method->out_parameters[j];
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0),
+ " <arg name=\"%s\" direction=\"out\" type=\"%s\"/>\n",
+ parameter->name, parameter->signature);
+ }
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0), " </method>\n");
+ }
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0),
+ " </interface>\n");
+
+ ref = container_of(ref->link.next,
+ struct wlsc_dbus_interface_ref, link);
+ }
+ byte_count += snprintf(buffer + byte_count, MAX(buffer_size - byte_count, 0), "</node>\n");
+
+ if (buffer == NULL) {
+ buffer_size = byte_count + 1;
+ buffer = malloc(buffer_size);
+ buffer[byte_count] = '\0';
+ goto fill_buffer;
+ }
+
+ return buffer;
+}
+
+static struct wlsc_dbus_method_parameter introspect_out_parameters[] = {
+ { "introspection_xml", "s" }
+};
+
+static struct wlsc_dbus_method introspectable_methods[] = {
+ { "Introspect",
+ NULL, 0,
+ introspect_out_parameters, ARRAY_LENGTH(introspect_out_parameters),
+ (wlsc_dbus_method_handler_t) introspect
+ }
+};
+
+static struct wlsc_dbus_interface introspectable_interface = {
+ DBUS_INTERFACE_INTROSPECTABLE ,
+ ARRAY_LENGTH(introspectable_methods),
+ introspectable_methods
+};
+
static void on_watch_data(int fd, uint32_t mask, void *data)
{
DBusWatch *watch = data;
@@ -204,10 +329,425 @@ static void on_dispatch_status_changed(DBusConnection *connection, DBusDispatchS
}
}
+static void unregister_object(DBusConnection *connection, void *user_data)
+{
+ struct wlsc_dbus *dbus = user_data;
+}
+
+static struct wlsc_dbus_method *wlsc_dbus_interface_lookup_method(struct wlsc_dbus_interface *interface, const char *method_name)
+{
+ int i;
+ for (i = 0; i < interface->method_count; i++) {
+ if (interface->methods[i].name == NULL)
+ continue;
+ if (strcmp(interface->methods[i].name, method_name) == 0)
+ return &interface->methods[i];
+ }
+ return NULL;
+}
+
+static struct wlsc_dbus_interface *wlsc_dbus_object_lookup_interface(struct wlsc_dbus_object *object, const char *interface_name)
+{
+ struct wlsc_dbus_interface_ref *ref;
+
+ ref = container_of(object->interface_list.next,
+ struct wlsc_dbus_interface_ref, link);
+ while (&ref->link != &object->interface_list) {
+
+ if (strcmp(ref->interface->name, interface_name) == 0)
+ return ref->interface;
+
+ ref = container_of(ref->link.next,
+ struct wlsc_dbus_interface_ref, link);
+ }
+
+ return NULL;
+}
+
+static struct wlsc_dbus_object *wlsc_dbus_lookup_object(struct wlsc_dbus *dbus, const char *path)
+{
+ struct wlsc_dbus_object_ref *ref;
+
+ ref = container_of(dbus->object_list.next,
+ struct wlsc_dbus_object_ref, link);
+ fprintf(stderr, "ref->link %p, object_list %p\n", &ref->link, &dbus->object_list);
+ while (&ref->link != &dbus->object_list) {
+
+ fprintf(stderr, "have %s need %s\n", ref->object->path, path);
+ if (strcmp(ref->object->path, path) == 0)
+ return ref->object;
+
+ ref = container_of(ref->link.next,
+ struct wlsc_dbus_object_ref, link);
+ }
+
+ return NULL;
+}
+
+static ffi_type *
+get_ffi_type_from_basic_dbus_type(int dbus_type)
+{
+ struct {
+ int dbus_type;
+ ffi_type *ffi_type;
+ } ffi_dbus_map[] = {
+ /* FIXME: handle all basic types */
+ { DBUS_TYPE_INVALID, &ffi_type_void },
+ { DBUS_TYPE_STRING, &ffi_type_pointer },
+ { DBUS_TYPE_ARRAY, &ffi_type_pointer },
+ { -1, NULL }
+ };
+ int i;
+
+ for (i = 0; ffi_dbus_map[i].dbus_type != -1; i++) {
+ if (ffi_dbus_map[i].dbus_type == dbus_type)
+ return ffi_dbus_map[i].ffi_type;
+ }
+
+ return NULL;
+}
+
+static int
+get_argument_count_for_method(struct wlsc_dbus_method *method)
+{
+ int i;
+ int argument_count;
+
+ argument_count = 0;
+
+ /* we use strlen as a shortcut because we currently only support
+ * basic types and 1d arrays. For basic types there is a 1 to 1
+ * correspondance between signature bytes and args (e.g., "i" -> int).
+ * For arrays there is a 2 to 2 correspondance
+ * (e.g., "ai" -> int *, unsigned long len)
+ */
+ for (i = 0; i < method->in_parameter_count; i++) {
+ argument_count += strlen(method->in_parameters[i].signature);
+ }
+
+ for (i = 0; i < method->out_parameter_count; i++) {
+ argument_count += strlen(method->out_parameters[i].signature);
+ }
+
+ return argument_count;
+}
+
+/* This function demarshals the passed in dbus method call message,
+ * marshals it back up in a form libffi can use, invokes the passed in
+ * method using libffi, marshals the out arguments into a dbus reply
+ * message and returns that reply. It's not complete, it only handles the
+ * subset of stuff that's needed right now.
+ *
+ * The convention is something like
+ *
+ * first_out_argument function(in args..., *remaining out args..., object)
+ *
+ * If this function is called on the global singleton object, then it hides
+ * the object argument and instead passes the method user_data.
+ *
+ * With the exception of arrays, each type in the dbus signature maps to
+ * one argument in the call. Arrays map to two arguments: type *data,
+ * unsigned long *length.
+ */
+static DBusMessage *wlsc_dbus_object_invoke_method_from_message(struct wlsc_dbus *dbus, struct wlsc_dbus_object *object, struct wlsc_dbus_method *method, DBusMessage *message)
+{
+ DBusMessage *reply;
+ DBusSignatureIter out_signature_iter;
+ DBusMessageIter message_iter;
+ ffi_cif cif;
+ ffi_arg return_value;
+ ffi_type *return_type;
+ ffi_type **parameter_types;
+ void **arguments;
+ void **out_argument_pointers;
+ int argument_count;
+ int dbus_type;
+ int i, first_out_argument;
+
+ /* count the number of in and out arguments from the method description */
+ argument_count = get_argument_count_for_method(method);
+
+ if (method->out_parameter_count > 0) {
+ /* use first out parameter for return value */
+ dbus_signature_iter_init(&out_signature_iter, method->out_parameters[0].signature);
+ dbus_type = dbus_signature_iter_get_current_type(&out_signature_iter);
+ return_type = get_ffi_type_from_basic_dbus_type(dbus_type);
+ argument_count--;
+
+ /* the allocation size is an approximation (but an upper bound), since
+ * one dbus array can expand into 2 ffi arguments */
+ out_argument_pointers = malloc(2 * method->out_parameter_count * sizeof (void *));
+ } else {
+ return_type = NULL;
+ out_argument_pointers = NULL;
+ }
+
+ parameter_types = malloc((argument_count + 1) * sizeof *parameter_types);
+ arguments = malloc((argument_count + 1) * sizeof *arguments);
+
+ i = 0;
+ /* convert message arguments to in args that ffi can use */
+ dbus_message_iter_init(message, &message_iter);
+ while ((dbus_type = dbus_message_iter_get_arg_type(&message_iter)) != DBUS_TYPE_INVALID) {
+ parameter_types[i] = get_ffi_type_from_basic_dbus_type(dbus_type);
+ dbus_message_iter_get_basic(&message_iter, &arguments[i]);
+ i++;
+ dbus_message_iter_next(&message_iter);
+ }
+
+ /* next add some pointers for the out args */
+ first_out_argument = i;
+ while (i < argument_count) {
+ parameter_types[i] = &ffi_type_pointer;
+ arguments[i] = &out_argument_pointers[i];
+ i++;
+ }
+
+ /* and finally, the object (or method user data if the object is opaque
+ * to the user) */
+ parameter_types[i] = &ffi_type_pointer;
+ if (object->is_opaque && method->private_data != NULL)
+ arguments[i] = &method->private_data;
+ else
+ arguments[i] = &object;
+ i++;
+
+ ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argument_count + 1, return_type, parameter_types);
+ ffi_call(&cif, method->function, &return_value, arguments);
+ reply = dbus_message_new_method_return(message);
+ dbus_message_iter_init_append(reply, &message_iter);
+
+ i = first_out_argument;
+ if (method->out_parameter_count > 0) {
+ int j = 0;
+
+ dbus_signature_iter_init(&out_signature_iter, method->out_parameters[j].signature);
+ j++;
+
+ dbus_type = dbus_signature_iter_get_current_type(&out_signature_iter);
+ if (dbus_type == DBUS_TYPE_ARRAY) {
+ DBusMessageIter array_iter;
+ DBusSignatureIter array_signature_iter;
+ int array_type;
+ char *array_signature;
+ const void *array;
+ unsigned long array_length;
+ dbus_signature_iter_recurse(&out_signature_iter, &array_signature_iter);
+ array_type = dbus_signature_iter_get_current_type(&array_signature_iter);
+ array_signature = dbus_signature_iter_get_signature(&array_signature_iter);
+ dbus_message_iter_open_container(&message_iter, DBUS_TYPE_ARRAY,
+ array_signature,
+ &array_iter);
+ dbus_free(array_signature);
+ array = (void *) return_value;
+ array_length = *(unsigned long *) out_argument_pointers[i - first_out_argument];
+ i++;
+ dbus_message_iter_append_fixed_array(&array_iter, array_type, &array, array_length);
+ dbus_message_iter_close_container(&message_iter, &array_iter);
+ } else if (dbus_type_is_basic(dbus_type)) {
+ dbus_message_iter_append_basic(&message_iter, dbus_type, &return_value);
+ }
+
+ while (j < method->out_parameter_count) {
+ dbus_signature_iter_init(&out_signature_iter, method->out_parameters[j].signature);
+ j++;
+
+ dbus_type = dbus_signature_iter_get_current_type(&out_signature_iter);
+ if (dbus_type == DBUS_TYPE_ARRAY) {
+ DBusMessageIter array_iter;
+ DBusSignatureIter array_signature_iter;
+ int array_type;
+ char *array_signature;
+ const void *array;
+ unsigned long array_length;
+ dbus_signature_iter_recurse(&out_signature_iter, &array_signature_iter);
+ array_type = dbus_signature_iter_get_current_type(&array_signature_iter);
+ array_signature = dbus_signature_iter_get_signature(&array_signature_iter);
+ dbus_message_iter_open_container(&message_iter, DBUS_TYPE_ARRAY,
+ array_signature,
+ &array_iter);
+ dbus_free(array_signature);
+ array = (void *) out_argument_pointers[i - first_out_argument];
+ i++;
+ array_length = *(unsigned long *) out_argument_pointers[i - first_out_argument];
+ i++;
+ dbus_message_iter_append_fixed_array(&array_iter, array_type, &array, array_length);
+ dbus_message_iter_close_container(&message_iter, &array_iter);
+ } else if (dbus_type_is_basic(dbus_type)) {
+ dbus_message_iter_append_basic(&message_iter, dbus_type, &arguments[i]);
+ i++;
+ }
+ }
+ }
+
+ free(parameter_types);
+ free(arguments);
+ free(out_argument_pointers);
+ return reply;
+}
+
+static bool wlsc_dbus_method_has_signature(struct wlsc_dbus_method *method, const char *signature)
+{
+ char *method_signature;
+ bool has_signature;
+ int i;
+ size_t offset;
+
+ if (signature[0] == '\0' || signature == NULL) {
+ return method->in_parameter_count == 0;
+ }
+
+ method_signature = malloc(2 * method->in_parameter_count);
+ method_signature[0] = '\0';
+ offset = 0;
+ for (i = 0; i < method->in_parameter_count; i++) {
+ offset += snprintf(method_signature + offset, 2,
+ method->in_parameters[i].signature);
+ }
+
+ has_signature = strcmp(method_signature, signature) == 0;
+ free(method_signature);
+
+ return has_signature;
+}
+
+static DBusHandlerResult on_message(DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+ struct wlsc_dbus *dbus = user_data;
+ const char *object_path, *interface_name, *method_name;
+ struct wlsc_dbus_object *object;
+ struct wlsc_dbus_interface *interface;
+ struct wlsc_dbus_method *method;
+ DBusError error;
+ DBusMessage *reply = NULL;
+ unsigned long sender_uid;
+
+ /* FIXME: we need to defer some of the guts of this function until
+ * we're able to ask PolicyKit if the user is allowed to talk to us.
+ * At an absolute minimum we should delay work until we asynchronously
+ * call GetConnetionUnixUser instead of using the blocking function below.
+ */
+ dbus_error_init(&error);
+ sender_uid = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
+ dbus_error_free(&error);
+
+ if (sender_uid != getuid()) {
+ struct passwd *passwd;
+ char *us = NULL, *them = NULL;
+
+ passwd = getpwuid(getuid());
+ if (passwd != NULL && passwd->pw_name != NULL)
+ asprintf(&us, "user '%s'", passwd->pw_name);
+ else
+ asprintf(&us, "uid %lu", (unsigned long) getuid());
+
+ passwd = getpwuid(sender_uid);
+ if (passwd != NULL && passwd->pw_name != NULL)
+ asprintf(&them, "user '%s'", passwd->pw_name);
+ else
+ asprintf(&them, "uid %lu", sender_uid);
+
+ reply = dbus_message_new_error_printf(message,
+ DBUS_ERROR_ACCESS_DENIED,
+ "must be %s not %s",
+ us, them);
+ free(us);
+ free(them);
+ goto done;
+ }
+
+ object_path = dbus_message_get_path(message);
+
+ if (object_path == NULL) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ object = wlsc_dbus_lookup_object(dbus, object_path);
+
+ if (object == NULL) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ interface_name = dbus_message_get_interface(message);
+ interface = wlsc_dbus_object_lookup_interface(object, interface_name);
+
+ if (interface == NULL) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ method_name = dbus_message_get_member(message);
+ method = wlsc_dbus_interface_lookup_method(interface, method_name);
+
+ if (method == NULL) {
+ reply = dbus_message_new_error_printf(message,
+ DBUS_ERROR_UNKNOWN_METHOD,
+ "unknown method '%s'", method_name);
+ goto done;
+ }
+
+ if (!wlsc_dbus_method_has_signature(method, dbus_message_get_signature(message))) {
+ reply = dbus_message_new_error_printf(message,
+ DBUS_ERROR_INVALID_ARGS,
+ "method '%s' called with incorrect arguments", method_name);
+ goto done;
+ }
+
+ reply = wlsc_dbus_object_invoke_method_from_message(dbus, object, method, message);
+done:
+ if (reply != NULL) {
+ dbus_connection_send(dbus->connection, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static struct DBusObjectPathVTable dbus_object_vtable = {
+ unregister_object,
+ on_message
+};
+
+struct wlsc_dbus_object *wlsc_dbus_object_create(void)
+{
+ struct wlsc_dbus_object *object;
+
+ object = malloc(sizeof *object);
+ if (object == NULL)
+ return NULL;
+
+ object->path = NULL;
+ wl_list_init(&object->interface_list);
+
+ object->is_opaque = false;
+
+ return object;
+}
+
+void wlsc_dbus_object_set_path(struct wlsc_dbus_object *object, const char *path)
+{
+ free(object->path);
+ object->path = strdup(path);
+}
+
+void wlsc_dbus_object_register_interface(struct wlsc_dbus_object *object, struct wlsc_dbus_interface *interface)
+{
+ struct wlsc_dbus_interface_ref *ref;
+
+ ref = malloc(sizeof *ref);
+
+ if (ref == NULL) {
+ return;
+ }
+
+ ref->interface = interface;
+ wl_list_insert(object->interface_list.prev, &ref->link);
+}
+
struct wlsc_dbus *
wlsc_dbus_init(struct wl_event_loop *loop)
{
struct wlsc_dbus *dbus;
+ struct wlsc_dbus_object_ref *ref;
DBusError error;
dbus = malloc(sizeof *dbus);
@@ -248,11 +788,32 @@ wlsc_dbus_init(struct wl_event_loop *loop)
dbus->dispatch_source = wl_event_loop_add_idle(dbus->loop, dispatch_idle, dbus);
if (!dbus_connection_add_filter(dbus->connection,
- wlsc_dbus_filter, dbus, NULL))
+ wlsc_dbus_filter, dbus, NULL)) {
+ free(dbus);
fprintf(stderr, "failed to add filter\n");
+ return NULL;
+ }
+
+ dbus_connection_register_object_path(dbus->connection,
+ SINGLETON_OBJECT_PATH,
+ &dbus_object_vtable,
+ dbus);
dbus_connection_set_exit_on_disconnect(dbus->connection, false);
+ wl_list_init(&dbus->object_list);
+
+ dbus->singleton_object = wlsc_dbus_object_create();
+ dbus->singleton_object->is_opaque = true;
+
+ wlsc_dbus_object_set_path(dbus->singleton_object, SINGLETON_OBJECT_PATH);
+ wlsc_dbus_object_register_interface(dbus->singleton_object, &singleton_object_interface);
+ wlsc_dbus_object_register_interface(dbus->singleton_object, &introspectable_interface);
+
+ ref = malloc(sizeof *ref);
+ ref->object = dbus->singleton_object;
+ wl_list_insert(dbus->object_list.prev, &ref->link);
+
return dbus;
}
@@ -279,3 +840,47 @@ bool wlsc_dbus_take_name(struct wlsc_dbus *dbus, const char *name, bool should_r
return result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
}
+
+void wlsc_dbus_register_method(struct wlsc_dbus *dbus, struct wlsc_dbus_method *method, void *user_data)
+{
+ struct wlsc_dbus_interface *interface;
+
+ interface = wlsc_dbus_object_lookup_interface(dbus->singleton_object, SINGLETON_OBJECT_INTERFACE);
+
+ if (interface->method_count >= MAX_METHODS_FOR_SINGLETON) {
+ fprintf(stderr, "dbus interface '"SINGLETON_OBJECT_INTERFACE"' has maximum number of methods registered\n");
+ return;
+ }
+
+ interface->methods[interface->method_count] = *method;
+ interface->methods[interface->method_count].private_data = user_data;
+ interface->method_count++;
+}
+
+void wlsc_dbus_register_object(struct wlsc_dbus *dbus, const char *path, struct wlsc_dbus_object *object)
+{
+ struct wlsc_dbus_object *old_object;
+ struct wlsc_dbus_object_ref *ref;
+
+ old_object = wlsc_dbus_lookup_object(dbus, object->path);
+
+ if (old_object != NULL) {
+ fprintf(stderr, "dbus object '%s' is already registered\n", object->path);
+ return;
+ }
+
+ ref = malloc(sizeof *ref);
+
+ if (ref == NULL) {
+ return;
+ }
+
+ ref->object = object;
+ wl_list_insert(dbus->object_list.prev, &ref->link);
+
+ dbus_connection_register_object_path(dbus->connection,
+ object->path,
+ &dbus_object_vtable,
+ dbus);
+}
+
diff --git a/wayland-system-compositor.h b/wayland-system-compositor.h
index 4b1b01e..f8d5fa0 100644
--- a/wayland-system-compositor.h
+++ b/wayland-system-compositor.h
@@ -29,6 +29,46 @@ wlsc_dbus_init(struct wl_event_loop *loop);
bool
wlsc_dbus_take_name(struct wlsc_dbus *dbus, const char *name, bool should_replace);
+typedef void (* wlsc_dbus_method_handler_t) (void);
+
+struct wlsc_dbus_method_parameter {
+ const char *name;
+ const char *signature;
+};
+
+struct wlsc_dbus_method {
+ const char *name;
+ struct wlsc_dbus_method_parameter *in_parameters;
+ int in_parameter_count;
+ struct wlsc_dbus_method_parameter *out_parameters;
+ int out_parameter_count;
+ wlsc_dbus_method_handler_t function;
+ void *private_data;
+};
+
+struct wlsc_dbus_interface {
+ const char *name;
+ int method_count;
+ struct wlsc_dbus_method *methods;
+};
+
+struct wlsc_dbus_object;
+
+struct wlsc_dbus_object *
+wlsc_dbus_object_create(void);
+
+void
+wlsc_dbus_object_set_path(struct wlsc_dbus_object *object, const char *path);
+
+void
+wlsc_dbus_object_register_interface(struct wlsc_dbus_object *object, struct wlsc_dbus_interface *interface);
+
+void
+wlsc_dbus_register_object(struct wlsc_dbus *dbus, const char *path, struct wlsc_dbus_object *object);
+
+void
+wlsc_dbus_register_method(struct wlsc_dbus *dbus, struct wlsc_dbus_method *method, void *user_data);
+
struct wlsc_input_device;
void
wlsc_device_get_position(struct wlsc_input_device *device, int32_t *x, int32_t *y);