diff options
author | Murray Cumming <murrayc@murrayc.com> | 2011-04-01 13:27:13 +0200 |
---|---|---|
committer | Murray Cumming <murrayc@murrayc.com> | 2011-04-01 13:27:13 +0200 |
commit | 99ed2652760b072174c4c45a1e7b8fad753c1dc2 (patch) | |
tree | 16aa021cfa4385d6129e7d595f56c3cd73eabd07 | |
parent | 55efa327a0c7a29ed2b4050dc9b081146d87ace3 (diff) | |
download | glibmm-99ed2652760b072174c4c45a1e7b8fad753c1dc2.tar.gz |
Added a simple example of a D-Bus session bus service.
* examples/dbus/session_bus_service.cc: This uses Gio::DBus::own_name().
* examples/Makefile.am: Mention the new test.
* examples/dbus/server.cc: Mention the return (out) value for the GetTime
method here too, and catch an exception.
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | examples/Makefile.am | 3 | ||||
-rw-r--r-- | examples/dbus/server.cc | 24 | ||||
-rw-r--r-- | examples/dbus/session_bus_service.cc | 208 | ||||
-rw-r--r-- | gio/src/dbusownname.hg | 1 |
5 files changed, 236 insertions, 9 deletions
@@ -1,5 +1,14 @@ 2011-04-01 Murray Cumming <murrayc@murrayc.com> + Added a simple example of a D-Bus session bus service. + + * examples/dbus/session_bus_service.cc: This uses Gio::DBus::own_name(). + * examples/Makefile.am: Mention the new test. + * examples/dbus/server.cc: Mention the return (out) value for the GetTime + method here too, and catch an exception. + +2011-04-01 Murray Cumming <murrayc@murrayc.com> + Gio::DBus: Minor API changes. * gio/src/dbusconnection.[hg|ccg]: register_object(), register_subtree(): diff --git a/examples/Makefile.am b/examples/Makefile.am index fa772e37..81cede23 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -20,6 +20,7 @@ AUTOMAKE_OPTIONS = subdir-objects check_PROGRAMS = \ child_watch/child_watch \ compose/example \ + dbus/session_bus_service \ dbus/server \ dbus/peer \ dbus/client_bus_listnames \ @@ -76,6 +77,8 @@ thread_threadpool_SOURCES = thread/threadpool.cc thread_threadpool_LDADD = $(thread_ldadd) # giomm examples +dbus_session_bus_service_SOURCES = dbus/session_bus_service.cc +dbus_session_bus_service_LDADD = $(giomm_ldadd) dbus_server_SOURCES = dbus/server.cc dbus_server_LDADD = $(giomm_ldadd) dbus_peer_SOURCES = dbus/peer.cc diff --git a/examples/dbus/server.cc b/examples/dbus/server.cc index 6ebe0ea9..b8956d1f 100644 --- a/examples/dbus/server.cc +++ b/examples/dbus/server.cc @@ -38,7 +38,9 @@ static Glib::RefPtr<Gio::DBus::NodeInfo> introspection_data; static Glib::ustring introspection_xml = "<node>" " <interface name='org.glibmm.DBus.Clock'>" - " <method name='GetTime' />" + " <method name='GetTime'>" + " <arg type='s' name='iso8601' direction='out'/>" + " </method>" " <method name='SetAlarm'>" " <arg type='s' name='iso8601' direction='in'/>" " </method>" @@ -142,6 +144,10 @@ static void on_method_call(const Glib::RefPtr<Gio::DBus::Connection>& connection } } +//This must be a global instance. See the InterfaceVTable documentation. +//TODO: Make that unnecessary. +const Gio::DBus::InterfaceVTable interface_vtable(sigc::ptr_fun(&on_method_call)); + bool on_server_new_connection(const Glib::RefPtr<Gio::DBus::Connection>& connection) { Glib::RefPtr<Gio::Credentials> credentials = @@ -176,15 +182,15 @@ bool on_server_new_connection(const Glib::RefPtr<Gio::DBus::Connection>& connect // See https://bugzilla.gnome.org/show_bug.cgi?id=646417 about avoiding // the repetition of the interface name: - const Gio::DBus::InterfaceVTable interface_vtable(sigc::ptr_fun(&on_method_call)); - const guint reg_id = connection->register_object("/org/glibmm/DBus/TestObject", - introspection_data->lookup_interface("org.glibmm.DBus.Clock"), - interface_vtable); - - if(reg_id == 0) + try + { + connection->register_object("/org/glibmm/DBus/TestObject", + introspection_data->lookup_interface("org.glibmm.DBus.Clock"), + interface_vtable); + } + catch(const Glib::Error& ex) { - std::cerr << "Registration of object for incoming connection not " - "possible." << std::endl; + std::cerr << "Registration of object failed." << std::endl; return false; } diff --git a/examples/dbus/session_bus_service.cc b/examples/dbus/session_bus_service.cc new file mode 100644 index 00000000..80cd4ba4 --- /dev/null +++ b/examples/dbus/session_bus_service.cc @@ -0,0 +1,208 @@ +/* Copyright (C) 2011 The giomm Development Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* This is a basic server providing a clock like functionality. Clients can + * get the current time, set the alarm and get notified when the alarm time is + * reached. It is basic because there is only one global alarm which any + * client can set. Clients listening for the alarm signal will be notified by + * use of the global alarm signal. The server should be easily modifiable to + * allow per-client alarms, but that is left as an exercise. + * + * Along with the above it provides a method to get its stdout's file + * descriptor to test the Gio::DBus::Message API. + */ + +#include <giomm.h> +#include <glibmm.h> +#include <iostream> + +namespace +{ + +static Glib::RefPtr<Gio::DBus::NodeInfo> introspection_data; + +static Glib::ustring introspection_xml = + "<node>" + " <interface name='org.glibmm.DBusExample.Clock'>" + " <method name='GetTime'>" + " <arg type='s' name='iso8601' direction='out'/>" + " </method>" + " <method name='SetAlarm'>" + " <arg type='s' name='iso8601' direction='in'/>" + " </method>" + " </interface>" + "</node>"; + +guint registered_id = 0; + +// Stores the current alarm. +static Glib::TimeVal curr_alarm; + +} // anonymous namespace + +static void on_method_call(const Glib::RefPtr<Gio::DBus::Connection>& connection, + const Glib::ustring& /* sender */, const Glib::ustring& /* object_path */, + const Glib::ustring& /* interface_name */, const Glib::ustring& method_name, + const Glib::VariantContainerBase& parameters, + const Glib::RefPtr<Gio::DBus::MethodInvocation>& invocation) +{ + if(method_name == "GetTime") + { + Glib::TimeVal curr_time; + curr_time.assign_current_time(); + + const Glib::ustring time_str = curr_time.as_iso8601(); + const Glib::Variant<Glib::ustring> time_var = + Glib::Variant<Glib::ustring>::create(time_str); + + // Create the tuple. + Glib::VariantContainerBase response = + Glib::VariantContainerBase::create_tuple(time_var); + + // Return the tuple with the included time. + invocation->return_value(response); + } + else if(method_name == "SetAlarm") + { + // Get the parameter tuple. + //Glib::VariantContainerBase parameters; + //invocation->get_parameters(parameters); + + // Get the variant string. + Glib::Variant<Glib::ustring> param; + parameters.get_child(param); + + // Get the time string. + const Glib::ustring time_str = param.get(); + + if(!curr_alarm.assign_from_iso8601(time_str)) + { + // If setting alarm was not successful, return an error. + Gio::DBus::Error error(Gio::DBus::Error::INVALID_ARGS, + "Alarm string is not in ISO8601 format."); + invocation->return_error(error); + } + } + else if(method_name == "GetStdout") + { +#ifndef G_OS_WIN32 + if(connection->get_capabilities() & + Gio::DBus::CAPABILITY_FLAGS_UNIX_FD_PASSING) + { + Glib::RefPtr<Gio::UnixFDList> list = Gio::UnixFDList::create(); + try + { + list->append(STDOUT_FILENO); + + Glib::RefPtr<Gio::DBus::Message> reply = + Gio::DBus::Message::create_method_reply(invocation->get_message()); + + reply->set_unix_fd_list(list); + + connection->send_message(reply); + } + catch(const Glib::Error& ex) + { + std::cerr << "Error trying to send stdout to client: " << ex.what() << + std::endl; + return; + } + } + else + { + invocation->return_dbus_error("org.glibmm.DBusExample.Failed", "Your message " + "bus daemon does not support file descriptor passing (need D-Bus >= " + "1.3.0)"); + } +#else + invocation->return_dbus_error("org.glibmm.DBusExample.Failed", "Your message bus " + "daemon does not support file descriptor passing (need D-Bus >= 1.3.0)"); +#endif + } + else + { + // Non-existent method on the interface. + Gio::DBus::Error error(Gio::DBus::Error::UNKNOWN_METHOD, + "Method does not exist."); + invocation->return_error(error); + } +} + +//This must be a global instance. See the InterfaceVTable documentation. +//TODO: Make that unnecessary. +const Gio::DBus::InterfaceVTable interface_vtable(sigc::ptr_fun(&on_method_call)); + +void on_bus_acquired(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& /* name */) +{ + // Export an object to the bus: + + // See https://bugzilla.gnome.org/show_bug.cgi?id=646417 about avoiding + // the repetition of the interface name: + try + { + registered_id = connection->register_object("/org/glibmm/DBus/TestObject", + introspection_data->lookup_interface("org.glibmm.DBusExample.Clock"), + interface_vtable); + } + catch(const Glib::Error& ex) + { + std::cerr << "Registration of object failed." << std::endl; + } + + return; +} + +void on_name_acquired(const Glib::RefPtr<Gio::DBus::Connection>& /* connection */, const Glib::ustring& /* name */) +{ + //TODO: What is this good for? See https://bugzilla.gnome.org/show_bug.cgi?id=646427 +} + +void on_name_lost(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& /* name */) +{ + connection->unregister_object(registered_id); +} + +int main(int, char**) +{ + std::locale::global(std::locale("")); + Gio::init(); + + try + { + introspection_data = Gio::DBus::NodeInfo::create_for_xml(introspection_xml); + } + catch(const Glib::Error& ex) + { + std::cerr << "Unable to create introspection data: " << ex.what() << + "." << std::endl; + return 1; + } + + const guint id = Gio::DBus::own_name(Gio::DBus::BUS_TYPE_SESSION, + "org.glibmm.DBusExample", + sigc::ptr_fun(&on_bus_acquired), + sigc::ptr_fun(&on_name_acquired), + sigc::ptr_fun(&on_name_lost)); + + //Keep the service running until the process is killed: + Glib::RefPtr<Glib::MainLoop> loop = Glib::MainLoop::create(); + loop->run(); + + Gio::DBus::unown_name(id); + + return EXIT_SUCCESS; +} diff --git a/gio/src/dbusownname.hg b/gio/src/dbusownname.hg index 39132b76..d34be5df 100644 --- a/gio/src/dbusownname.hg +++ b/gio/src/dbusownname.hg @@ -51,6 +51,7 @@ typedef sigc::slot<void, const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustri */ typedef sigc::slot<void, const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring> SlotNameLost; +//TODO: See https://bugzilla.gnome.org/show_bug.cgi?id=646427 about the apparent uselessness of SlotNameAcquired. //TODO: Add example from C API in class docs. /** Starts acquiring @a name on the bus specified by @a bus_type and calls @a * name_acquired_slot and name_@a lost_slot when the name is acquired |