summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMurray Cumming <murrayc@murrayc.com>2011-04-01 13:27:13 +0200
committerMurray Cumming <murrayc@murrayc.com>2011-04-01 13:27:13 +0200
commit99ed2652760b072174c4c45a1e7b8fad753c1dc2 (patch)
tree16aa021cfa4385d6129e7d595f56c3cd73eabd07
parent55efa327a0c7a29ed2b4050dc9b081146d87ace3 (diff)
downloadglibmm-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--ChangeLog9
-rw-r--r--examples/Makefile.am3
-rw-r--r--examples/dbus/server.cc24
-rw-r--r--examples/dbus/session_bus_service.cc208
-rw-r--r--gio/src/dbusownname.hg1
5 files changed, 236 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 68317c3e..e3152efd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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