| #include <gio/gio.h> | |
| #include <stdlib.h> | |
| #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| /* The object we want to export */ | |
| typedef struct _MyObjectClass MyObjectClass; | |
| typedef struct _MyObject MyObject; | |
| struct _MyObjectClass | |
| { | |
| GObjectClass parent_class; | |
| }; | |
| struct _MyObject | |
| { | |
| GObject parent_instance; | |
| gint count; | |
| gchar *name; | |
| }; | |
| enum | |
| { | |
| PROP_0, | |
| PROP_COUNT, | |
| PROP_NAME | |
| }; | |
| static GType my_object_get_type (void); | |
| G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT) | |
| static void | |
| my_object_finalize (GObject *object) | |
| { | |
| MyObject *myobj = (MyObject*)object; | |
| g_free (myobj->name); | |
| G_OBJECT_CLASS (my_object_parent_class)->finalize (object); | |
| } | |
| static void | |
| my_object_init (MyObject *object) | |
| { | |
| object->count = 0; | |
| object->name = NULL; | |
| } | |
| static void | |
| my_object_get_property (GObject *object, | |
| guint prop_id, | |
| GValue *value, | |
| GParamSpec *pspec) | |
| { | |
| MyObject *myobj = (MyObject*)object; | |
| switch (prop_id) | |
| { | |
| case PROP_COUNT: | |
| g_value_set_int (value, myobj->count); | |
| break; | |
| case PROP_NAME: | |
| g_value_set_string (value, myobj->name); | |
| break; | |
| default: | |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
| } | |
| } | |
| static void | |
| my_object_set_property (GObject *object, | |
| guint prop_id, | |
| const GValue *value, | |
| GParamSpec *pspec) | |
| { | |
| MyObject *myobj = (MyObject*)object; | |
| switch (prop_id) | |
| { | |
| case PROP_COUNT: | |
| myobj->count = g_value_get_int (value); | |
| break; | |
| case PROP_NAME: | |
| g_free (myobj->name); | |
| myobj->name = g_value_dup_string (value); | |
| break; | |
| default: | |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
| } | |
| } | |
| static void | |
| my_object_class_init (MyObjectClass *class) | |
| { | |
| GObjectClass *gobject_class = G_OBJECT_CLASS (class); | |
| gobject_class->finalize = my_object_finalize; | |
| gobject_class->set_property = my_object_set_property; | |
| gobject_class->get_property = my_object_get_property; | |
| g_object_class_install_property (gobject_class, | |
| PROP_COUNT, | |
| g_param_spec_int ("count", | |
| "Count", | |
| "Count", | |
| 0, 99999, 0, | |
| G_PARAM_READWRITE)); | |
| g_object_class_install_property (gobject_class, | |
| PROP_NAME, | |
| g_param_spec_string ("name", | |
| "Name", | |
| "Name", | |
| NULL, | |
| G_PARAM_READWRITE)); | |
| } | |
| /* A method that we want to export */ | |
| static void | |
| my_object_change_count (MyObject *myobj, | |
| gint change) | |
| { | |
| myobj->count = 2 * myobj->count + change; | |
| g_object_notify (G_OBJECT (myobj), "count"); | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static GDBusNodeInfo *introspection_data = NULL; | |
| /* Introspection data for the service we are exporting */ | |
| static const gchar introspection_xml[] = | |
| "<node>" | |
| " <interface name='org.myorg.MyObject'>" | |
| " <method name='ChangeCount'>" | |
| " <arg type='i' name='change' direction='in'/>" | |
| " </method>" | |
| " <property type='i' name='Count' access='read'/>" | |
| " <property type='s' name='Name' access='readwrite'/>" | |
| " </interface>" | |
| "</node>"; | |
| static void | |
| handle_method_call (GDBusConnection *connection, | |
| const gchar *sender, | |
| const gchar *object_path, | |
| const gchar *interface_name, | |
| const gchar *method_name, | |
| GVariant *parameters, | |
| GDBusMethodInvocation *invocation, | |
| gpointer user_data) | |
| { | |
| MyObject *myobj = user_data; | |
| if (g_strcmp0 (method_name, "ChangeCount") == 0) | |
| { | |
| gint change; | |
| g_variant_get (parameters, "(i)", &change); | |
| my_object_change_count (myobj, change); | |
| g_dbus_method_invocation_return_value (invocation, NULL); | |
| } | |
| } | |
| static GVariant * | |
| handle_get_property (GDBusConnection *connection, | |
| const gchar *sender, | |
| const gchar *object_path, | |
| const gchar *interface_name, | |
| const gchar *property_name, | |
| GError **error, | |
| gpointer user_data) | |
| { | |
| GVariant *ret; | |
| MyObject *myobj = user_data; | |
| ret = NULL; | |
| if (g_strcmp0 (property_name, "Count") == 0) | |
| { | |
| ret = g_variant_new_int32 (myobj->count); | |
| } | |
| else if (g_strcmp0 (property_name, "Name") == 0) | |
| { | |
| ret = g_variant_new_string (myobj->name ? myobj->name : ""); | |
| } | |
| return ret; | |
| } | |
| static gboolean | |
| handle_set_property (GDBusConnection *connection, | |
| const gchar *sender, | |
| const gchar *object_path, | |
| const gchar *interface_name, | |
| const gchar *property_name, | |
| GVariant *value, | |
| GError **error, | |
| gpointer user_data) | |
| { | |
| MyObject *myobj = user_data; | |
| if (g_strcmp0 (property_name, "Count") == 0) | |
| { | |
| g_object_set (myobj, "count", g_variant_get_int32 (value), NULL); | |
| } | |
| else if (g_strcmp0 (property_name, "Name") == 0) | |
| { | |
| g_object_set (myobj, "name", g_variant_get_string (value, NULL), NULL); | |
| } | |
| return TRUE; | |
| } | |
| /* for now */ | |
| static const GDBusInterfaceVTable interface_vtable = | |
| { | |
| handle_method_call, | |
| handle_get_property, | |
| handle_set_property, | |
| { 0 } | |
| }; | |
| static void | |
| send_property_change (GObject *obj, | |
| GParamSpec *pspec, | |
| GDBusConnection *connection) | |
| { | |
| GVariantBuilder *builder; | |
| GVariantBuilder *invalidated_builder; | |
| MyObject *myobj = (MyObject *)obj; | |
| builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); | |
| invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); | |
| if (g_strcmp0 (pspec->name, "count") == 0) | |
| g_variant_builder_add (builder, | |
| "{sv}", | |
| "Count", g_variant_new_int32 (myobj->count)); | |
| else if (g_strcmp0 (pspec->name, "name") == 0) | |
| g_variant_builder_add (builder, | |
| "{sv}", | |
| "Name", g_variant_new_string (myobj->name ? myobj->name : "")); | |
| g_dbus_connection_emit_signal (connection, | |
| NULL, | |
| "/org/myorg/MyObject", | |
| DBUS_INTERFACE_PROPERTIES, | |
| "PropertiesChanged", | |
| g_variant_new ("(sa{sv}as)", | |
| "org.myorg.MyObject", | |
| builder, | |
| invalidated_builder), | |
| NULL); | |
| } | |
| static void | |
| on_bus_acquired (GDBusConnection *connection, | |
| const gchar *name, | |
| gpointer user_data) | |
| { | |
| MyObject *myobj = user_data; | |
| guint registration_id; | |
| g_signal_connect (myobj, "notify", | |
| G_CALLBACK (send_property_change), connection); | |
| registration_id = g_dbus_connection_register_object (connection, | |
| "/org/myorg/MyObject", | |
| introspection_data->interfaces[0], | |
| &interface_vtable, | |
| myobj, | |
| NULL, /* user_data_free_func */ | |
| NULL); /* GError** */ | |
| g_assert (registration_id > 0); | |
| } | |
| static void | |
| on_name_acquired (GDBusConnection *connection, | |
| const gchar *name, | |
| gpointer user_data) | |
| { | |
| } | |
| static void | |
| on_name_lost (GDBusConnection *connection, | |
| const gchar *name, | |
| gpointer user_data) | |
| { | |
| exit (1); | |
| } | |
| int | |
| main (int argc, char *argv[]) | |
| { | |
| guint owner_id; | |
| GMainLoop *loop; | |
| MyObject *myobj; | |
| /* We are lazy here - we don't want to manually provide | |
| * the introspection data structures - so we just build | |
| * them from XML. | |
| */ | |
| introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); | |
| g_assert (introspection_data != NULL); | |
| myobj = g_object_new (my_object_get_type (), NULL); | |
| owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, | |
| "org.myorg.MyObject", | |
| G_BUS_NAME_OWNER_FLAGS_NONE, | |
| on_bus_acquired, | |
| on_name_acquired, | |
| on_name_lost, | |
| myobj, | |
| NULL); | |
| loop = g_main_loop_new (NULL, FALSE); | |
| g_main_loop_run (loop); | |
| g_bus_unown_name (owner_id); | |
| g_dbus_node_info_unref (introspection_data); | |
| g_object_unref (myobj); | |
| return 0; | |
| } |