[glib] gdbus: Add a way to emit a signal



commit 0b41002474abd7a95c53b76fba937a922aa0ea86
Author: David Zeuthen <davidz redhat com>
Date:   Sat Jun 4 12:33:39 2011 -0400

    gdbus: Add a way to emit a signal
    
    See https://bugs.freedesktop.org/show_bug.cgi?id=37890#c6 where it was
    discovered that dbus-send(1) actually doesn't work (either libdbus-1's
    flush implementation or dbus-send(1)'s usage of it is broken) so it's
    useful to have here.
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 docs/reference/gio/gdbus.xml |   43 ++++++++-
 gio/gdbus-tool.c             |  203 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 242 insertions(+), 4 deletions(-)
---
diff --git a/docs/reference/gio/gdbus.xml b/docs/reference/gio/gdbus.xml
index 75e7eeb..fdccee2 100644
--- a/docs/reference/gio/gdbus.xml
+++ b/docs/reference/gio/gdbus.xml
@@ -8,7 +8,7 @@
 
 <refnamediv>
   <refname>gdbus</refname>
-  <refpurpose>Introspect and call remote objects</refpurpose>
+  <refpurpose>Tool for working with D-Bus objects</refpurpose>
 </refnamediv>
 
 <refsynopsisdiv>
@@ -56,6 +56,22 @@
   </cmdsynopsis>
   <cmdsynopsis>
     <command>gdbus</command>
+    <arg choice="plain">emit</arg>
+    <group>
+      <arg choice="plain">--system</arg>
+      <arg choice="plain">--session</arg>
+      <arg choice="plain">--address <replaceable>address</replaceable></arg>
+    </group>
+    <arg choice="plain">--object-path <replaceable>/path/to/object</replaceable></arg>
+    <arg choice="plain">--signal <replaceable>org.project.InterfaceName.SignalName</replaceable></arg>
+    <group>
+      <arg choice="plain">--dest <replaceable>unique_bus_name</replaceable></arg>
+    </group>
+    <arg choice="plain">ARG1</arg>
+    <arg choice="plain" rep="repeat">ARG2</arg>
+  </cmdsynopsis>
+  <cmdsynopsis>
+    <command>gdbus</command>
     <arg choice="plain">help</arg>
   </cmdsynopsis>
 </refsynopsisdiv>
@@ -63,8 +79,7 @@
 <refsect1>
   <title>Description</title>
   <para>
-    <command>gdbus</command> offers a simple commandline utility for
-    introspecting and calling methods on remote objects.
+    <command>gdbus</command> is a simple tool for working with D-Bus objects.
   </para>
   <refsect2>
     <title>Commands</title>
@@ -96,6 +111,14 @@
         </para></listitem>
       </varlistentry>
       <varlistentry>
+        <term><option>emit</option></term>
+        <listitem><para>
+          Emits a signal. Each argument to include in the signal must be specified as a serialized
+          <link linkend="GVariant"><type>GVariant</type></link> except that strings do
+          not need explicit quotes.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
         <term><option>help</option></term>
         <listitem><para>
           Prints help and exit.
@@ -238,6 +261,20 @@ The name org.freedesktop.NetworkManager is owned by :1.5
 /org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': &lt;byte 0x64&gt;},)
 </programlisting>
 
+<para>
+  Emitting a signal:
+</para>
+<programlisting>
+$ gdbus emit --session --o /foo -s org.bar.Foo "['foo', 'bar', 'baz']"
+</programlisting>
+
+<para>
+  Emitting a signal to a specific process:
+</para>
+<programlisting>
+$ gdbus emit --session --o /foo -s org.bar.Foo someString --dest :1.3
+</programlisting>
+
 </refsect1>
 
 <refsect1>
diff --git a/gio/gdbus-tool.c b/gio/gdbus-tool.c
index 9228122..9fb52fc 100644
--- a/gio/gdbus-tool.c
+++ b/gio/gdbus-tool.c
@@ -95,6 +95,7 @@ usage (gint *argc, gchar **argv[], gboolean use_stdout)
                          "  introspect   Introspect a remote object\n"
                          "  monitor      Monitor a remote object\n"
                          "  call         Invoke a method on a remote object\n"
+                         "  emit         Emit a signal\n"
                          "\n"
                          "Use \"%s COMMAND --help\" to get help on each command.\n"),
                        program_name);
@@ -524,6 +525,196 @@ _g_variant_parse_me_harder (GVariantType   *type,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static gchar *opt_emit_dest = NULL;
+static gchar *opt_emit_object_path = NULL;
+static gchar *opt_emit_signal = NULL;
+
+static const GOptionEntry emit_entries[] =
+{
+  { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
+  { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
+  { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
+  { NULL }
+};
+
+static gboolean
+handle_emit (gint        *argc,
+             gchar      **argv[],
+             gboolean     request_completion,
+             const gchar *completion_cur,
+             const gchar *completion_prev)
+{
+  gint ret;
+  GOptionContext *o;
+  gchar *s;
+  GError *error;
+  GDBusConnection *c;
+  GVariant *parameters;
+  gchar *interface_name;
+  gchar *signal_name;
+  GVariantBuilder builder;
+  guint n;
+
+  ret = FALSE;
+  c = NULL;
+  parameters = NULL;
+  interface_name = NULL;
+  signal_name = NULL;
+
+  modify_argv0_for_command (argc, argv, "emit");
+
+  o = g_option_context_new (NULL);
+  g_option_context_set_help_enabled (o, FALSE);
+  g_option_context_set_summary (o, _("Emit a signal."));
+  g_option_context_add_main_entries (o, emit_entries, GETTEXT_PACKAGE);
+  g_option_context_add_group (o, connection_get_group ());
+
+  if (!g_option_context_parse (o, argc, argv, NULL))
+    {
+      if (!request_completion)
+        {
+          s = g_option_context_get_help (o, FALSE, NULL);
+          g_printerr ("%s", s);
+          g_free (s);
+          goto out;
+        }
+    }
+
+  error = NULL;
+  c = connection_get_dbus_connection (&error);
+  if (c == NULL)
+    {
+      if (request_completion)
+        {
+          if (g_strcmp0 (completion_prev, "--address") == 0)
+            {
+              g_print ("unix:\n"
+                       "tcp:\n"
+                       "nonce-tcp:\n");
+            }
+          else
+            {
+              g_print ("--system \n--session \n--address \n");
+            }
+        }
+      else
+        {
+          g_printerr (_("Error connecting: %s\n"), error->message);
+          g_error_free (error);
+        }
+      goto out;
+    }
+
+  /* All done with completion now */
+  if (request_completion)
+    goto out;
+
+  if (opt_emit_object_path == NULL)
+    {
+      g_printerr (_("Error: object path not specified.\n"));
+      goto out;
+    }
+  if (!g_variant_is_object_path (opt_emit_object_path))
+    {
+      g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
+      goto out;
+    }
+
+  if (opt_emit_signal == NULL)
+    {
+      g_printerr (_("Error: signal not specified.\n"));
+      goto out;
+    }
+  s = strrchr (opt_emit_signal, '.');
+  signal_name = g_strdup (s + 1);
+  interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
+
+  if (!g_dbus_is_interface_name (interface_name))
+    {
+      g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
+      goto out;
+    }
+
+  if (!g_dbus_is_member_name (signal_name))
+    {
+      g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
+      goto out;
+    }
+
+  if (opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
+    {
+      g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
+      goto out;
+    }
+
+  /* Read parameters */
+  g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
+  for (n = 1; n < (guint) *argc; n++)
+    {
+      GVariant *value;
+
+      error = NULL;
+      value = g_variant_parse (NULL,
+                               (*argv)[n],
+                               NULL,
+                               NULL,
+                               &error);
+      if (value == NULL)
+        {
+          g_error_free (error);
+          error = NULL;
+          value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
+          if (value == NULL)
+            {
+              g_printerr (_("Error parsing parameter %d: %s\n"),
+                          n,
+                          error->message);
+              g_error_free (error);
+              g_variant_builder_clear (&builder);
+              goto out;
+            }
+        }
+      g_variant_builder_add_value (&builder, value);
+    }
+  parameters = g_variant_builder_end (&builder);
+
+  if (parameters != NULL)
+    parameters = g_variant_ref_sink (parameters);
+  if (!g_dbus_connection_emit_signal (c,
+                                      opt_emit_dest,
+                                      opt_emit_object_path,
+                                      interface_name,
+                                      signal_name,
+                                      parameters,
+                                      &error))
+    {
+      g_printerr (_("Error: %s\n"), error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  if (!g_dbus_connection_flush_sync (c, NULL, &error))
+    {
+      g_printerr (_("Error flushing connection: %s\n"), error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  ret = TRUE;
+
+ out:
+  if (c != NULL)
+    g_object_unref (c);
+  if (parameters != NULL)
+    g_variant_unref (parameters);
+  g_free (interface_name);
+  g_free (signal_name);
+  g_option_context_free (o);
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gchar *opt_call_dest = NULL;
 static gchar *opt_call_object_path = NULL;
 static gchar *opt_call_method = NULL;
@@ -1698,6 +1889,16 @@ main (gint argc, gchar *argv[])
         }
       goto out;
     }
+  else if (g_strcmp0 (command, "emit") == 0)
+    {
+      if (handle_emit (&argc,
+                       &argv,
+                       request_completion,
+                       completion_cur,
+                       completion_prev))
+        ret = 0;
+      goto out;
+    }
   else if (g_strcmp0 (command, "call") == 0)
     {
       if (handle_call (&argc,
@@ -1797,7 +1998,7 @@ main (gint argc, gchar *argv[])
     {
       if (request_completion)
         {
-          g_print ("help \ncall \nintrospect \nmonitor \n");
+          g_print ("help \nemit \ncall \nintrospect \nmonitor \n");
           ret = 0;
           goto out;
         }



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