[glibmm] Added a simple example of a D-Bus session bus service.



commit 99ed2652760b072174c4c45a1e7b8fad753c1dc2
Author: Murray Cumming <murrayc murrayc com>
Date:   Fri Apr 1 13:27:13 2011 +0200

    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.

 ChangeLog                            |    9 ++
 examples/Makefile.am                 |    3 +
 examples/dbus/server.cc              |   24 +++--
 examples/dbus/session_bus_service.cc |  208 ++++++++++++++++++++++++++++++++++
 gio/src/dbusownname.hg               |    1 +
 5 files changed, 236 insertions(+), 9 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 68317c3..e3152ef 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 fa772e3..81cede2 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 6ebe0ea..b8956d1 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 0000000..80cd4ba
--- /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 39132b7..d34be5d 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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]