/** * server-v1 * A really simple D-Bus server, intended as the initial example * in a D-Bus server tutorial. This server *pretends* to supply one * method, HelloWorld, but does not implement that method. * * Copyright (c) 2013 Samuel A. Rebelsky. All rights reserved. * * This file is part of The Glimmer Guide to Writing a D-Bus Server. * * The Glimmer Guide to Writing a D-Bus Server is free software: you * can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * The Glimmer Guide to Writing a D-Bus Server is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software. If not, see . */ // +-------+----------------------------------------------------------- // | Notes | // +-------+ /* o This server provides a single object that provides no methods. */ // +---------+--------------------------------------------------------- // | Headers | // +---------+ #include #include #include #include // +--------------------------+---------------------------------------- // | Function Predeclarations | // +--------------------------+ // +---------+--------------------------------------------------------- // | Globals | // +---------+ /** * The service name on the bus. */ static const gchar service[] = "edu.grinnell.glimmer.guide.SampleServer1"; /** * The object we publish on the bus. */ static const gchar object_name[] = "/edu/grinnell/glimmer/guide/SampleObject1"; /** * Introspection data for the one object, in the internal form. * (This will get filled in later.) */ static GDBusNodeInfo *introspection_data = NULL; /** * Introspection data for the one object in XML form (somewhat human * readable, somewhat computer readable). */ static const gchar introspection_xml[] = "" " " " " " " " " " " ""; // +------------------+------------------------------------------------ // | Object Callbacks | // +------------------+ /** * Handle a request for a property. (Parameters should be obvious.) */ 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) { // Print an optional log message #ifdef VERBOSE fprintf (stderr, "[server 1] " "handle_get_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",(error),%p)\n", connection, sender, object_path, interface_name, property_name, user_data); #endif // We currently don't have any properties, so this should be an // error. g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "[server 1] Invalid property '%s'", property_name); // And we're done return NULL; } // handle_get_property /** * Handle a call to a method. (Parameters should be obvious.) */ 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) { #ifdef VERBOSE gchar *paramstr = g_variant_print (parameters, TRUE); fprintf (stderr, "[server 1] " "handle_method_call (%p,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",(invocation),%p)\n", connection, sender, object_path, interface_name, method_name, paramstr, user_data); g_free (paramstr); #endif // Default: No such mehotd g_dbus_method_invocation_return_error (invocation, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "[server 1] Invalid method: '%s'", method_name); } // handle_method_call /** * Handle a request to set a property. */ 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) { // Print an optional log message #ifdef VERBOSE gchar *valstr = g_variant_print (value, TRUE); fprintf (stderr, "[server 1] " "handle_set_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",(error),%p)\n", connection, sender, object_path, interface_name, property_name, valstr, user_data); g_free (valstr); #endif g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "[server 1] Invalid property: '%s'", property_name); return 0; } // handle_set_property // +---------------+--------------------------------------------------- // | Bus Callbacks | // +---------------+ /** * What to do when the bus gets acquired. */ static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { static GDBusInterfaceVTable interface_vtable = { handle_method_call, handle_get_property, handle_set_property }; guint registration_id; GError *error = NULL; // A bit of (optional) notification #ifdef VERBOSE fprintf (stderr, "[server 1] on_bus_acquired (%p, \"%s\", %p)\n", connection, name, user_data); #endif registration_id = g_dbus_connection_register_object (connection, object_name, introspection_data->interfaces[0], &interface_vtable, NULL, // Optional user data NULL, // Func. for freeing user data &error); // Should check to see whether or not the call succeeded. Oh well. } // on_bus_acquired static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { // A bit of (optional) notification #ifdef VERBOSE fprintf (stderr, "[server 1] on_name_acquired (%p, \"%s\", %p)\n", connection, name, user_data); #endif } // on_name_acquired static void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) { // A bit of (optional) notification #ifdef VERBOSE fprintf (stderr, "[server 1] on_name_lost (%p, \"%s\", %p)\n", connection, name, user_data); #endif // Things seem to have gone badly wrong, so give up exit (1); } // on_name_lost // +------+------------------------------------------------------------ // | Main | // +------+ int main (int argc, char *argv[]) { guint owner_id; GMainLoop *loop; // Set up glib. g_type_init (); // Build an internal representation of the interface introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); // Request the name on the bus owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, service, G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); // Start the main loop loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); // Tell the bus that we're done with the name g_bus_unown_name (owner_id); // Clean up after ourselves g_dbus_node_info_unref (introspection_data); // And we're done return 0; } // main