| #include <gio/gio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static GDBusNodeInfo *introspection_data = NULL; | |
| static GDBusInterfaceInfo *manager_interface_info = NULL; | |
| static GDBusInterfaceInfo *block_interface_info = NULL; | |
| static GDBusInterfaceInfo *partition_interface_info = NULL; | |
| /* Introspection data for the service we are exporting */ | |
| static const gchar introspection_xml[] = | |
| "<node>" | |
| " <interface name='org.gtk.GDBus.Example.Manager'>" | |
| " <method name='Hello'>" | |
| " <arg type='s' name='greeting' direction='in'/>" | |
| " <arg type='s' name='response' direction='out'/>" | |
| " </method>" | |
| " </interface>" | |
| " <interface name='org.gtk.GDBus.Example.Block'>" | |
| " <method name='Hello'>" | |
| " <arg type='s' name='greeting' direction='in'/>" | |
| " <arg type='s' name='response' direction='out'/>" | |
| " </method>" | |
| " <property type='i' name='Major' access='read'/>" | |
| " <property type='i' name='Minor' access='read'/>" | |
| " <property type='s' name='Notes' access='readwrite'/>" | |
| " </interface>" | |
| " <interface name='org.gtk.GDBus.Example.Partition'>" | |
| " <method name='Hello'>" | |
| " <arg type='s' name='greeting' direction='in'/>" | |
| " <arg type='s' name='response' direction='out'/>" | |
| " </method>" | |
| " <property type='i' name='PartitionNumber' access='read'/>" | |
| " <property type='s' name='Notes' access='readwrite'/>" | |
| " </interface>" | |
| "</node>"; | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static void | |
| manager_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) | |
| { | |
| const gchar *greeting; | |
| gchar *response; | |
| g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Manager"); | |
| g_assert_cmpstr (method_name, ==, "Hello"); | |
| g_variant_get (parameters, "(&s)", &greeting); | |
| response = g_strdup_printf ("Method %s.%s with user_data '%s' on object path %s called with arg '%s'", | |
| interface_name, | |
| method_name, | |
| (const gchar *) user_data, | |
| object_path, | |
| greeting); | |
| g_dbus_method_invocation_return_value (invocation, | |
| g_variant_new ("(s)", response)); | |
| g_free (response); | |
| } | |
| const GDBusInterfaceVTable manager_vtable = | |
| { | |
| manager_method_call, | |
| NULL, /* get_property */ | |
| NULL, /* set_property */ | |
| { 0 } | |
| }; | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static void | |
| block_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) | |
| { | |
| g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Block"); | |
| if (g_strcmp0 (method_name, "Hello") == 0) | |
| { | |
| const gchar *greeting; | |
| gchar *response; | |
| g_variant_get (parameters, "(&s)", &greeting); | |
| response = g_strdup_printf ("Method %s.%s with user_data '%s' on object path %s called with arg '%s'", | |
| interface_name, | |
| method_name, | |
| (const gchar *) user_data, | |
| object_path, | |
| greeting); | |
| g_dbus_method_invocation_return_value (invocation, | |
| g_variant_new ("(s)", response)); | |
| g_free (response); | |
| } | |
| else if (g_strcmp0 (method_name, "DoStuff") == 0) | |
| { | |
| g_dbus_method_invocation_return_dbus_error (invocation, | |
| "org.gtk.GDBus.TestSubtree.Error.Failed", | |
| "This method intentionally always fails"); | |
| } | |
| else | |
| { | |
| g_assert_not_reached (); | |
| } | |
| } | |
| static GVariant * | |
| block_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; | |
| const gchar *node; | |
| gint major; | |
| gint minor; | |
| node = strrchr (object_path, '/') + 1; | |
| if (g_str_has_prefix (node, "sda")) | |
| major = 8; | |
| else | |
| major = 9; | |
| if (strlen (node) == 4) | |
| minor = node[3] - '0'; | |
| else | |
| minor = 0; | |
| ret = NULL; | |
| if (g_strcmp0 (property_name, "Major") == 0) | |
| { | |
| ret = g_variant_new_int32 (major); | |
| } | |
| else if (g_strcmp0 (property_name, "Minor") == 0) | |
| { | |
| ret = g_variant_new_int32 (minor); | |
| } | |
| else if (g_strcmp0 (property_name, "Notes") == 0) | |
| { | |
| g_set_error (error, | |
| G_IO_ERROR, | |
| G_IO_ERROR_FAILED, | |
| "Hello %s. I thought I said reading this property " | |
| "always results in an error. kthxbye", | |
| sender); | |
| } | |
| else | |
| { | |
| g_assert_not_reached (); | |
| } | |
| return ret; | |
| } | |
| static gboolean | |
| block_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) | |
| { | |
| /* TODO */ | |
| g_assert_not_reached (); | |
| } | |
| const GDBusInterfaceVTable block_vtable = | |
| { | |
| block_method_call, | |
| block_get_property, | |
| block_set_property, | |
| { 0 } | |
| }; | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static void | |
| partition_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) | |
| { | |
| const gchar *greeting; | |
| gchar *response; | |
| g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Partition"); | |
| g_assert_cmpstr (method_name, ==, "Hello"); | |
| g_variant_get (parameters, "(&s)", &greeting); | |
| response = g_strdup_printf ("Method %s.%s with user_data '%s' on object path %s called with arg '%s'", | |
| interface_name, | |
| method_name, | |
| (const gchar *) user_data, | |
| object_path, | |
| greeting); | |
| g_dbus_method_invocation_return_value (invocation, | |
| g_variant_new ("(s)", response)); | |
| g_free (response); | |
| } | |
| const GDBusInterfaceVTable partition_vtable = | |
| { | |
| partition_method_call, | |
| NULL, | |
| NULL, | |
| { 0 } | |
| }; | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static gchar ** | |
| subtree_enumerate (GDBusConnection *connection, | |
| const gchar *sender, | |
| const gchar *object_path, | |
| gpointer user_data) | |
| { | |
| gchar **nodes; | |
| GPtrArray *p; | |
| p = g_ptr_array_new (); | |
| g_ptr_array_add (p, g_strdup ("sda")); | |
| g_ptr_array_add (p, g_strdup ("sda1")); | |
| g_ptr_array_add (p, g_strdup ("sda2")); | |
| g_ptr_array_add (p, g_strdup ("sda3")); | |
| g_ptr_array_add (p, g_strdup ("sdb")); | |
| g_ptr_array_add (p, g_strdup ("sdb1")); | |
| g_ptr_array_add (p, g_strdup ("sdc")); | |
| g_ptr_array_add (p, g_strdup ("sdc1")); | |
| g_ptr_array_add (p, NULL); | |
| nodes = (gchar **) g_ptr_array_free (p, FALSE); | |
| return nodes; | |
| } | |
| static GDBusInterfaceInfo ** | |
| subtree_introspect (GDBusConnection *connection, | |
| const gchar *sender, | |
| const gchar *object_path, | |
| const gchar *node, | |
| gpointer user_data) | |
| { | |
| GPtrArray *p; | |
| p = g_ptr_array_new (); | |
| if (node == NULL) | |
| { | |
| g_ptr_array_add (p, g_dbus_interface_info_ref (manager_interface_info)); | |
| } | |
| else | |
| { | |
| g_ptr_array_add (p, g_dbus_interface_info_ref (block_interface_info)); | |
| if (strlen (node) == 4) | |
| g_ptr_array_add (p, | |
| g_dbus_interface_info_ref (partition_interface_info)); | |
| } | |
| g_ptr_array_add (p, NULL); | |
| return (GDBusInterfaceInfo **) g_ptr_array_free (p, FALSE); | |
| } | |
| static const GDBusInterfaceVTable * | |
| subtree_dispatch (GDBusConnection *connection, | |
| const gchar *sender, | |
| const gchar *object_path, | |
| const gchar *interface_name, | |
| const gchar *node, | |
| gpointer *out_user_data, | |
| gpointer user_data) | |
| { | |
| const GDBusInterfaceVTable *vtable_to_return; | |
| gpointer user_data_to_return; | |
| if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Manager") == 0) | |
| { | |
| user_data_to_return = "The Root"; | |
| vtable_to_return = &manager_vtable; | |
| } | |
| else | |
| { | |
| if (strlen (node) == 4) | |
| user_data_to_return = "A partition"; | |
| else | |
| user_data_to_return = "A block device"; | |
| if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Block") == 0) | |
| vtable_to_return = &block_vtable; | |
| else if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Partition") == 0) | |
| vtable_to_return = &partition_vtable; | |
| else | |
| g_assert_not_reached (); | |
| } | |
| *out_user_data = user_data_to_return; | |
| return vtable_to_return; | |
| } | |
| const GDBusSubtreeVTable subtree_vtable = | |
| { | |
| subtree_enumerate, | |
| subtree_introspect, | |
| subtree_dispatch, | |
| { 0 } | |
| }; | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static void | |
| on_bus_acquired (GDBusConnection *connection, | |
| const gchar *name, | |
| gpointer user_data) | |
| { | |
| guint registration_id; | |
| registration_id = g_dbus_connection_register_subtree (connection, | |
| "/org/gtk/GDBus/TestSubtree/Devices", | |
| &subtree_vtable, | |
| G_DBUS_SUBTREE_FLAGS_NONE, | |
| NULL, /* user_data */ | |
| 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; | |
| /* 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); | |
| manager_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Manager"); | |
| block_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Block"); | |
| partition_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Partition"); | |
| g_assert (manager_interface_info != NULL); | |
| g_assert (block_interface_info != NULL); | |
| g_assert (partition_interface_info != NULL); | |
| owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, | |
| "org.gtk.GDBus.TestSubtree", | |
| G_BUS_NAME_OWNER_FLAGS_NONE, | |
| on_bus_acquired, | |
| on_name_acquired, | |
| on_name_lost, | |
| NULL, | |
| 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); | |
| return 0; | |
| } |