[glib/wip/application: 4/11] GApplication: add remote commandline support



commit b0d6a55dca00291f2c5e38ec32e074605e08d04f
Author: Ryan Lortie <desrt desrt ca>
Date:   Sat Oct 9 17:24:09 2010 -0400

    GApplication: add remote commandline support

 gio/Makefile.am                       |    2 +
 gio/gapplication.c                    |   88 +++++++++--
 gio/gapplication.h                    |    5 +-
 gio/gapplicationcommandline.c         |  273 +++++++++++++++++++++++++++++++++
 gio/gapplicationcommandline.h         |  120 +++++++++++++++
 gio/gapplicationimpl-dbus-interface.c |   36 +++++-
 gio/gapplicationimpl-dbus.c           |  234 +++++++++++++++++++++++++++-
 gio/gapplicationimpl.h                |    5 +
 gio/gio-marshal.list                  |    1 +
 gio/gio.h                             |    1 +
 gio/gioenums.h                        |    7 +-
 11 files changed, 748 insertions(+), 24 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 50a5aed..fb09051 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -139,6 +139,7 @@ application_headers = \
 	gsimpleactiongroup.h		\
 	gaction.h			\
 	gsimpleaction.h			\
+	gapplicationcommandline.h	\
 	gapplication.h
 
 application_sources = \
@@ -146,6 +147,7 @@ application_sources = \
 	gsimpleactiongroup.c			\
 	gaction.c				\
 	gsimpleaction.c				\
+	gapplicationcommandline.c		\
 	gapplicationimpl-dbus.c			\
 	gapplication.c
 
diff --git a/gio/gapplication.c b/gio/gapplication.c
index 27d60b6..3652fb9 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -22,6 +22,7 @@
 /* Prologue {{{1 */
 #include "gapplication.h"
 
+#include "gapplicationcommandline.h"
 #include "gapplicationimpl.h"
 
 #include "gioenumtypes.h"
@@ -132,12 +133,30 @@ g_application_real_open (GApplication  *application,
     }
 }
 
+static int
+g_application_real_command_line (GApplication            *application,
+                                 GApplicationCommandLine *cmdline)
+{
+  static gboolean warned;
+
+  if (warned) 
+    return 1;
+
+  g_warning ("Your application claims to support custom command line "
+             "handling but does not implement g_application_command_line() "
+             "and has no handlers connected to the 'command-line' signal.");
+
+  warned = TRUE;
+
+  return 1;
+}
+
 static gboolean
 g_application_real_local_command_line (GApplication  *application,
                                        GVariant     **arguments,
                                        int           *exit_status)
 {
-  if (0)
+  if (application->priv->flags & G_APPLICATION_HANDLES_COMMAND_LINE)
     return FALSE;
 
   else
@@ -155,12 +174,12 @@ g_application_real_local_command_line (GApplication  *application,
 
       n_args = g_variant_n_children (*arguments);
 
-      if (application->priv->flags & G_APPLICATION_FLAGS_IS_SERVICE)
+      if (application->priv->flags & G_APPLICATION_IS_SERVICE)
         {
           if (n_args > 1)
             {
               g_printerr ("GApplication service mode takes no arguments.\n");
-              application->priv->flags &= ~G_APPLICATION_FLAGS_IS_SERVICE;
+              application->priv->flags &= ~G_APPLICATION_IS_SERVICE;
             }
 
           return TRUE;
@@ -174,7 +193,7 @@ g_application_real_local_command_line (GApplication  *application,
 
       else
         {
-          if (~application->priv->flags & G_APPLICATION_FLAGS_HANDLES_OPEN)
+          if (~application->priv->flags & G_APPLICATION_HANDLES_OPEN)
             {
               g_critical ("This application can not open files.");
               *exit_status = 1;
@@ -330,6 +349,17 @@ g_application_init (GApplication *application)
                                                    GApplicationPrivate);
 }
 
+static gboolean
+first_wins_accumulator (GSignalInvocationHint *ihint,
+                        GValue                *return_accu,
+                        const GValue          *handler_return,
+                        gpointer               data)
+{
+  g_value_copy (handler_return, return_accu);
+
+  return FALSE;
+}
+
 static void
 g_application_class_init (GApplicationClass *class)
 {
@@ -345,6 +375,7 @@ g_application_class_init (GApplicationClass *class)
   class->startup = g_application_real_startup;
   class->activate = g_application_real_activate;
   class->open = g_application_real_open;
+  class->command_line = g_application_real_command_line;
   class->local_command_line = g_application_real_local_command_line;
   class->add_platform_data = g_application_real_add_platform_data;
   class->quit_mainloop = g_application_real_quit_mainloop;
@@ -394,6 +425,12 @@ g_application_class_init (GApplicationClass *class)
                   NULL, NULL, _gio_marshal_VOID__POINTER_INT_STRING,
                   G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_STRING);
 
+  g_application_signals[SIGNAL_COMMAND_LINE] =
+    g_signal_new ("command-line", G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GApplicationClass, command_line),
+                  first_wins_accumulator, NULL, _gio_marshal_INT__OBJECT,
+                  G_TYPE_INT, 1, G_TYPE_APPLICATION_COMMAND_LINE);
+
   g_type_class_add_private (class, sizeof (GApplicationPrivate));
 }
 
@@ -729,9 +766,9 @@ g_application_register (GApplication  *application,
       gboolean try;
 
       /* don't try to be the primary instance if
-       * G_APPLICATION_FLAGS_IS_LAUNCHER was specified.
+       * G_APPLICATION_IS_LAUNCHER was specified.
        */
-      try = !(application->priv->flags & G_APPLICATION_FLAGS_IS_LAUNCHER);
+      try = !(application->priv->flags & G_APPLICATION_IS_LAUNCHER);
 
       application->priv->impl =
         g_application_impl_register (application, application->priv->id,
@@ -867,7 +904,7 @@ g_application_activate (GApplication *application)
  * for this functionality, you should use "".
  *
  * The application must be registered before calling this function and
- * it must have the %G_APPLICATION_FLAGS_CAN_OPEN flag set.  The open()
+ * it must have the %G_APPLICATION_CAN_OPEN flag set.  The open()
  * virtual function should also be implemented in order for anything
  * meaningful to happen.
  *
@@ -881,7 +918,7 @@ g_application_open (GApplication  *application,
 {
   g_return_if_fail (G_IS_APPLICATION (application));
   g_return_if_fail (application->priv->flags &
-                    G_APPLICATION_FLAGS_HANDLES_OPEN);
+                    G_APPLICATION_HANDLES_OPEN);
   g_return_if_fail (application->priv->is_registered);
 
   if (application->priv->is_remote)
@@ -913,7 +950,7 @@ g_application_open (GApplication  *application,
  * virtual function is invoked in the primary instance (which may or may
  * not be this instance).
  *
- * If the application has the %G_APPLICATION_FLAGS_REMOTE_COMMAND_LINE
+ * If the application has the %G_APPLICATION_REMOTE_COMMAND_LINE
  * flag set then the default implementation of handle_command_line()
  * always returns %FALSE immediately, resulting in the commandline
  * always being handled in the primary instance.
@@ -924,7 +961,7 @@ g_application_open (GApplication  *application,
  * to register the application.  If that works, then the command line
  * arguments are inspected.  If no commandline arguments are given, then
  * g_application_activate() is called.  If commandline arguments are
- * given and the %G_APPLICATION_FLAGS_CAN_OPEN flags is set then they
+ * given and the %G_APPLICATION_CAN_OPEN flags is set then they
  * are assumed to be filenames and g_application_open() is called.
  *
  * If you are interested in doing more complicated local handling of the
@@ -984,12 +1021,39 @@ g_application_run_with_arguments (GApplication *application,
   if (!G_APPLICATION_GET_CLASS (application)
         ->local_command_line (application, &arguments, &status))
     {
-      g_assert_not_reached ();
+      GError *error = NULL;
+
+      if (!g_application_register (application, NULL, &error))
+        {
+          g_printerr ("%s", error->message);
+          g_error_free (error);
+          return 1;
+        }
+
+      if (application->priv->is_remote)
+        {
+          GVariant *platform_data;
+
+          platform_data = get_platform_data (application);
+          status = g_application_impl_command_line (application->priv->impl,
+                                                    arguments, platform_data);
+        }
+      else
+        {
+          GApplicationCommandLine *cmdline;
+
+          cmdline = g_object_new (G_TYPE_APPLICATION_COMMAND_LINE,
+                                  "arguments", arguments, NULL);
+          g_signal_emit (application,
+                         g_application_signals[SIGNAL_COMMAND_LINE],
+                         0, cmdline, &status);
+          g_object_unref (cmdline);
+        }
     }
 
   g_variant_unref (arguments);
 
-  if (application->priv->flags & G_APPLICATION_FLAGS_IS_SERVICE &&
+  if (application->priv->flags & G_APPLICATION_IS_SERVICE &&
       !application->priv->use_count &&
       !application->priv->inactivity_timeout_id)
     {
diff --git a/gio/gapplication.h b/gio/gapplication.h
index 4e5dc20..dcaedd7 100644
--- a/gio/gapplication.h
+++ b/gio/gapplication.h
@@ -93,15 +93,14 @@ struct _GApplicationClass
                                                      gint                      n_files,
                                                      const gchar              *hint);
 
-  gpointer _reserved_1;
+  int                       (* command_line)        (GApplication             *application,
+                                                     GApplicationCommandLine  *command_line);
 
   /* vfuncs */
   gboolean                  (* local_command_line)  (GApplication             *application,
                                                      GVariant                **arguments,
                                                      int                      *exit_status);
 
-  gpointer _reserved_2;
-
   void                      (* before_emit)         (GApplication             *application,
                                                      GVariant                 *platform_data);
   void                      (* after_emit)          (GApplication             *application,
diff --git a/gio/gapplicationcommandline.c b/gio/gapplicationcommandline.c
new file mode 100644
index 0000000..af9d7a8
--- /dev/null
+++ b/gio/gapplicationcommandline.c
@@ -0,0 +1,273 @@
+#include "gapplicationcommandline.h"
+
+#include <string.h>
+#include <stdio.h>
+
+G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
+
+enum
+{
+  PROP_NONE,
+  PROP_ARGUMENTS,
+  PROP_PLATFORM_DATA,
+  PROP_IS_REMOTE
+};
+
+struct _GApplicationCommandLinePrivate
+{
+  GVariant *platform_data;
+  GVariant *arguments;
+  GVariant *cwd;
+  gint exit_status;
+};
+
+#define IS_REMOTE(cmdline) ((cmdline)->priv->platform_data != NULL)
+
+void
+g_application_command_line_get_argc_argv (GApplicationCommandLine   *cmdline,
+                                          int                       *argc,
+                                          char                    ***argv)
+{
+  gsize len;
+
+  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
+  g_return_if_fail (argc != NULL && argv != NULL);
+
+  *argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
+  *argc = len;
+}
+
+GVariant *
+g_application_command_line_get_arguments (GApplicationCommandLine *cmdline)
+{
+  return g_variant_ref (cmdline->priv->arguments);
+}
+
+const gchar *
+g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
+{
+  if (cmdline->priv->cwd)
+    return g_variant_get_bytestring (cmdline->priv->cwd);
+  else
+    return NULL;
+}
+
+GVariant *
+g_application_command_line_get_cwd_variant (GApplicationCommandLine *cmdline)
+{
+  if (cmdline->priv->cwd)
+    return g_variant_ref (cmdline->priv->cwd);
+  else
+    return NULL;
+}
+
+gboolean
+g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
+{
+  return IS_REMOTE (cmdline);
+}
+
+static void
+g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
+                                               const gchar             *message)
+{
+  g_print ("%s\n", message);
+}
+
+static void
+g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
+                                                  const gchar             *message)
+{
+  g_printerr ("%s\n", message);
+}
+
+void
+g_application_command_line_print (GApplicationCommandLine *cmdline,
+                                  const gchar             *format,
+                                  ...)
+{
+  gchar *message;
+  va_list ap;
+
+  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
+  g_return_if_fail (format != NULL);
+
+  va_start (ap, format);
+  message = g_strdup_vprintf (format, ap);
+  va_end (ap);
+
+  G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
+    ->print_literal (cmdline, message);
+  g_free (message);
+}
+
+void
+g_application_command_line_printerr (GApplicationCommandLine *cmdline,
+                                     const gchar             *format,
+                                     ...)
+{
+  gchar *message;
+  va_list ap;
+
+  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
+  g_return_if_fail (format != NULL);
+
+  va_start (ap, format);
+  message = g_strdup_vprintf (format, ap);
+  va_end (ap);
+
+  G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
+    ->printerr_literal (cmdline, message);
+  g_free (message);
+}
+
+void
+g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
+                                            int                      exit_status)
+{
+  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
+
+  cmdline->priv->exit_status = exit_status;
+}
+
+int
+g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
+{
+  g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
+
+  return cmdline->priv->exit_status;
+}
+
+static void
+grok_platform_data (GApplicationCommandLine *cmdline)
+{
+  GVariantIter iter;
+  const gchar *key;
+  GVariant *value;
+
+  g_variant_iter_init (&iter, cmdline->priv->platform_data);
+
+  while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
+    if (strcmp (key, "cwd") == 0)
+      {
+        if (!cmdline->priv->cwd)
+          cmdline->priv->cwd = g_variant_ref (value);
+      }
+}
+
+static void
+g_application_command_line_get_property (GObject *object, guint prop_id,
+                                         GValue *value, GParamSpec *pspec)
+{
+  GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
+
+  switch (prop_id)
+    {
+    case PROP_ARGUMENTS:
+      g_value_set_variant (value, cmdline->priv->arguments);
+      break;
+
+    case PROP_PLATFORM_DATA:
+      g_value_set_variant (value, cmdline->priv->platform_data);
+      break;
+
+    case PROP_IS_REMOTE:
+      g_value_set_boolean (value, IS_REMOTE (cmdline));
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
+g_application_command_line_set_property (GObject *object, guint prop_id,
+                                         const GValue *value, GParamSpec *pspec)
+{
+  GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
+
+  switch (prop_id)
+    {
+    case PROP_ARGUMENTS:
+      g_assert (cmdline->priv->arguments == NULL);
+      cmdline->priv->arguments = g_value_dup_variant (value);
+      break;
+
+    case PROP_PLATFORM_DATA:
+      g_assert (cmdline->priv->platform_data == NULL);
+      cmdline->priv->platform_data = g_value_dup_variant (value);
+      if (cmdline->priv->platform_data != NULL)
+        grok_platform_data (cmdline);
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
+g_application_command_line_finalize (GObject *object)
+{
+  GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
+
+  if (cmdline->priv->platform_data)
+    g_variant_unref (cmdline->priv->platform_data);
+  if (cmdline->priv->arguments)
+    g_variant_unref (cmdline->priv->arguments);
+  if (cmdline->priv->cwd)
+    g_variant_unref (cmdline->priv->cwd);
+
+  G_OBJECT_CLASS (g_application_command_line_parent_class)
+    ->finalize (object);
+}
+
+static void
+g_application_command_line_init (GApplicationCommandLine *cmdline)
+{
+  cmdline->priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (cmdline,
+                                 G_TYPE_APPLICATION_COMMAND_LINE,
+                                 GApplicationCommandLinePrivate);
+}
+
+static void
+g_application_command_line_class_init (GApplicationCommandLineClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->get_property = g_application_command_line_get_property;
+  object_class->set_property = g_application_command_line_set_property;
+  object_class->finalize = g_application_command_line_finalize;
+  class->printerr_literal = g_application_command_line_real_printerr_literal;
+  class->print_literal = g_application_command_line_real_print_literal;
+
+  g_object_class_install_property (object_class, PROP_ARGUMENTS,
+    g_param_spec_variant ("arguments", "commandline arguments",
+                          "the commandline that caused this cmdline",
+                          G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
+                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
+    g_param_spec_variant ("platform-data", "platform data",
+                          "platform-specific data for the cmdline",
+                          G_VARIANT_TYPE ("a{sv}"), NULL,
+                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_IS_REMOTE,
+    g_param_spec_boolean ("is-remote", "is remote",
+                          "TRUE if this is a remote cmdline", FALSE,
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_type_class_add_private (class, sizeof (GApplicationCommandLinePrivate));
+}
+
+GVariant *
+g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
+{
+  g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
+  g_return_val_if_fail (IS_REMOTE (cmdline), NULL);
+
+  return g_variant_ref (cmdline->priv->platform_data);
+}
diff --git a/gio/gapplicationcommandline.h b/gio/gapplicationcommandline.h
new file mode 100644
index 0000000..f0547b0
--- /dev/null
+++ b/gio/gapplicationcommandline.h
@@ -0,0 +1,120 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2010 Codethink Limited
+ *
+ * This program 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 of the licence 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_APPLICATION_COMMAND_LINE_H__
+#define __G_APPLICATION_COMMAND_LINE_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_APPLICATION_COMMAND_LINE                     (g_application_command_line_get_type ())
+#define G_APPLICATION_COMMAND_LINE(inst)                    (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_APPLICATION_COMMAND_LINE,                        \
+                                                             GApplicationCommandLine))
+#define G_APPLICATION_COMMAND_LINE_CLASS(class)             (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_APPLICATION_COMMAND_LINE,                        \
+                                                             GApplicationCommandLineClass))
+#define G_IS_APPLICATION_COMMAND_LINE(inst)                 (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_APPLICATION_COMMAND_LINE))
+#define G_IS_APPLICATION_COMMAND_LINE_CLASS(class)          (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_APPLICATION_COMMAND_LINE))
+#define G_APPLICATION_COMMAND_LINE_GET_CLASS(inst)          (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_APPLICATION_COMMAND_LINE,                        \
+                                                             GApplicationCommandLineClass))
+
+typedef struct _GApplicationCommandLinePrivate               GApplicationCommandLinePrivate;
+typedef struct _GApplicationCommandLineClass                 GApplicationCommandLineClass;
+
+/**
+ * GApplicationCommandLine:
+ *
+ * The <structname>GApplicationCommandLine</structname> structure contains private
+ * data and should only be accessed using the provided API
+ *
+ * Since: 2.26
+ */
+struct _GApplicationCommandLine
+{
+  /*< private >*/
+  GObject parent_instance;
+
+  GApplicationCommandLinePrivate *priv;
+};
+
+/**
+ * GApplicationCommandLineClass:
+ *
+ * The <structname>GApplicationCommandLineClass</structname> structure contains
+ * private data only
+ *
+ * Since: 2.26
+ */
+struct _GApplicationCommandLineClass
+{
+  /*< private >*/
+  GObjectClass parent_class;
+
+  void (* print_literal)    (GApplicationCommandLine *command_line,
+                             const gchar             *message);
+  void (* printerr_literal) (GApplicationCommandLine *command_line,
+                             const gchar             *message);
+
+  gpointer padding[12];
+};
+
+GType                   g_application_command_line_get_type             (void) G_GNUC_CONST;
+
+void                    g_application_command_line_get_argc_argv        (GApplicationCommandLine   *command_line,
+                                                                         int                       *argc,
+                                                                         char                    ***argv);
+GVariant *              g_application_command_line_get_arguments        (GApplicationCommandLine   *command_line);
+
+const gchar *           g_application_command_line_get_cwd              (GApplicationCommandLine   *command_line);
+GVariant *              g_application_command_line_get_cwd_variant      (GApplicationCommandLine   *command_line);
+
+gboolean                g_application_command_line_get_is_remote        (GApplicationCommandLine   *command_line);
+
+void                    g_application_command_line_output               (GApplicationCommandLine   *command_line,
+                                                                         gint                       fd,
+                                                                         gconstpointer              buffer,
+                                                                         gssize                     length);
+void                    g_application_command_line_print                (GApplicationCommandLine   *command_line,
+                                                                         const gchar               *format,
+                                                                         ...);
+void                    g_application_command_line_printerr             (GApplicationCommandLine   *command_line,
+                                                                         const gchar               *format,
+                                                                         ...);
+
+int                     g_application_command_line_get_exit_status      (GApplicationCommandLine   *command_line);
+void                    g_application_command_line_set_exit_status      (GApplicationCommandLine   *command_line,
+                                                                         int                        exit_status);
+
+GVariant *              g_application_command_line_get_platform_data    (GApplicationCommandLine   *command_line);
+
+G_END_DECLS
+
+#endif /* __G_APPLICATION_COMMAND_LINE_H__ */
diff --git a/gio/gapplicationimpl-dbus-interface.c b/gio/gapplicationimpl-dbus-interface.c
index 022fdf7..900a7db 100644
--- a/gio/gapplicationimpl-dbus-interface.c
+++ b/gio/gapplicationimpl-dbus-interface.c
@@ -37,6 +37,9 @@ static const GDBusArgInfo *activate_out[] = { NULL };
 static const GDBusArgInfo *open_in[] = { &open_uris_arg, &open_hint_arg, &platform_data_arg, NULL };
 static const GDBusArgInfo *open_out[] = { NULL };
 
+static const GDBusArgInfo *cmdline_in[] = { &cmdline_path_arg, &cmdline_arguments_arg, &platform_data_arg, NULL };
+static const GDBusArgInfo *cmdline_out[] = { &cmdline_exit_status_arg, NULL };
+
 static const GDBusMethodInfo activate_method = {
   -1, (gchar *) "Activate",
   (GDBusArgInfo **) activate_in,
@@ -49,11 +52,42 @@ static const GDBusMethodInfo open_method = {
   (GDBusArgInfo **) open_out
 };
 
+static const GDBusMethodInfo command_line_method = {
+  -1, (gchar *) "CommandLine",
+  (GDBusArgInfo **) cmdline_in,
+  (GDBusArgInfo **) cmdline_out
+};
+
 static const GDBusMethodInfo *application_methods[] = {
-  &activate_method, &open_method, NULL
+  &activate_method, &open_method, &command_line_method, NULL
 };
 
 const GDBusInterfaceInfo org_gtk_Application = {
   -1, (gchar *) "org.gtk.Application",
   (GDBusMethodInfo **) application_methods
 };
+
+static const GDBusArgInfo message_arg = { -1, (gchar *) "message", (gchar *) "s" };
+static const GDBusArgInfo *print_in[] = { &message_arg, NULL };
+static const GDBusArgInfo *print_out[] = { NULL };
+
+static const GDBusMethodInfo stdout_method = {
+  -1, (gchar *) "Print",
+  (GDBusArgInfo **) print_in,
+  (GDBusArgInfo **) print_out
+};
+
+static const GDBusMethodInfo stderr_method = {
+  -1, (gchar *) "PrintError",
+  (GDBusArgInfo **) print_in,
+  (GDBusArgInfo **) print_out
+};
+
+static const GDBusMethodInfo *cmdline_methods[] = {
+  &stdout_method, &stderr_method, NULL
+};
+
+const GDBusInterfaceInfo org_gtk_private_Cmdline = {
+  -1, (gchar *) "org.gtk.private.CommandLine",
+  (GDBusMethodInfo **) cmdline_methods
+};
diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c
index c271f37..1f6a360 100644
--- a/gio/gapplicationimpl-dbus.c
+++ b/gio/gapplicationimpl-dbus.c
@@ -28,9 +28,11 @@
 #include "gdbuserror.h"
 
 #include <string.h>
-
+#include <stdio.h>
 
 #include "gapplicationimpl-dbus-interface.c"
+#include "gapplicationcommandline.h"
+#include "gdbusmethodinvocation.h"
 
 struct _GApplicationImpl
 {
@@ -39,10 +41,13 @@ struct _GApplicationImpl
   gchar           *object_path;
   guint            object_id;
   gpointer         app;
-
-  GMainLoop       *cmdline_mainloop;
 };
 
+
+static GApplicationCommandLine *
+g_dbus_command_line_new (GDBusMethodInvocation *invocation);
+
+
 static void
 g_application_impl_method_call (GDBusConnection       *connection,
                                 const gchar           *sender,
@@ -104,6 +109,22 @@ g_application_impl_method_call (GDBusConnection       *connection,
       g_free (files);
     }
 
+  else if (strcmp (method_name, "CommandLine") == 0)
+    {
+      GApplicationCommandLine *cmdline;
+      GVariant *platform_data;
+      int status;
+
+      cmdline = g_dbus_command_line_new (invocation);
+      platform_data = g_variant_get_child_value (parameters, 2);
+      class->before_emit (impl->app, platform_data);
+      g_signal_emit_by_name (impl->app, "command-line", cmdline, &status);
+      g_application_command_line_set_exit_status (cmdline, status);
+      class->after_emit (impl->app, platform_data);
+      g_variant_unref (platform_data);
+      g_object_unref (cmdline);
+    }
+
   else
     g_assert_not_reached ();
 }
@@ -175,7 +196,7 @@ g_application_impl_register (GApplication       *application,
 
   impl->object_path = application_path_from_appid (appid);
 
-  if (flags & G_APPLICATION_FLAGS_IS_LAUNCHER)
+  if (flags & G_APPLICATION_IS_LAUNCHER)
     {
       impl->object_id = 0;
       *is_remote = TRUE;
@@ -238,7 +259,7 @@ g_application_impl_register (GApplication       *application,
                                            impl->object_id);
       impl->object_id = 0;
 
-      if (flags & G_APPLICATION_FLAGS_IS_SERVICE)
+      if (flags & G_APPLICATION_IS_SERVICE)
         {
           g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
                        "Unable to acquire bus name `%s'", appid);
@@ -297,8 +318,211 @@ g_application_impl_open (GApplicationImpl  *impl,
                           NULL, 0, -1, NULL, NULL, NULL);
 }
 
+static void
+g_application_impl_cmdline_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)
+{
+  const gchar *message;
+
+  g_variant_get_child (parameters, 0, "&s", &message);
+
+  if (strcmp (method_name, "Print") == 0)
+    g_print ("%s", message);
+  else if (strcmp (method_name, "PrintError") == 0)
+    g_printerr ("%s", message);
+  else
+    g_assert_not_reached ();
+
+  g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+typedef struct
+{
+  GMainLoop *loop;
+  int status;
+} CommandLineData;
+
+static void
+g_application_impl_cmdline_done (GObject      *source,
+                                 GAsyncResult *result,
+                                 gpointer      user_data)
+{
+  CommandLineData *data = user_data;
+  GError *error = NULL;
+  GVariant *reply;
+
+  reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
+                                         result, &error);
+
+  if (reply != NULL)
+    {
+      g_variant_get (reply, "(i)", &data->status);
+      g_variant_unref (reply);
+    }
+
+  else
+    {
+      g_printerr ("%s\n", error->message);
+      g_error_free (error);
+      data->status = 1;
+    }
+
+  g_main_loop_quit (data->loop);
+}
+
+int
+g_application_impl_command_line (GApplicationImpl *impl,
+                                 GVariant         *arguments,
+                                 GVariant         *platform_data)
+{
+  const static GDBusInterfaceVTable vtable = {
+    g_application_impl_cmdline_method_call
+  };
+  const gchar *object_path = "/org/gtk/Application/CommandLine";
+  GMainContext *context;
+  CommandLineData data;
+  guint object_id;
+
+  context = g_main_context_new ();
+  data.loop = g_main_loop_new (context, FALSE);
+  g_main_context_push_thread_default (context);
+
+  object_id = g_dbus_connection_register_object (impl->session_bus,
+                                                 object_path,
+                                                 (GDBusInterfaceInfo *)
+                                                   &org_gtk_private_Cmdline,
+                                                 &vtable, &data, NULL, NULL);
+  /* In theory we should try other paths... */
+  g_assert (object_id != 0);
+
+  g_dbus_connection_call (impl->session_bus,
+                          impl->bus_name,
+                          impl->object_path,
+                          "org.gtk.Application",
+                          "CommandLine",
+                          g_variant_new ("(o aay@a{sv})", object_path,
+                                         arguments, platform_data),
+                          G_VARIANT_TYPE ("(i)"), 0, -1, NULL,
+                          g_application_impl_cmdline_done, &data);
+
+  g_main_loop_run (data.loop);
+
+  g_main_context_pop_thread_default (context);
+  g_main_context_unref (context);
+  g_main_loop_unref (data.loop);
+
+  return data.status;
+}
+
 void
 g_application_impl_flush (GApplicationImpl *impl)
 {
   g_dbus_connection_flush_sync (impl->session_bus, NULL, NULL);
 }
+
+
+
+
+
+typedef GApplicationCommandLineClass GDBusCommandLineClass;
+static GType g_dbus_command_line_get_type (void);
+typedef struct
+{
+  GApplicationCommandLine  parent_instance;
+  GDBusMethodInvocation   *invocation;
+
+  GDBusConnection *connection;
+  const gchar     *bus_name;
+  const gchar     *object_path;
+} GDBusCommandLine;
+
+
+G_DEFINE_TYPE (GDBusCommandLine,
+               g_dbus_command_line,
+               G_TYPE_APPLICATION_COMMAND_LINE)
+
+static void
+g_dbus_command_line_print_literal (GApplicationCommandLine *cmdline,
+                                   const gchar             *message)
+{
+  GDBusCommandLine *gdbcl = (GDBusCommandLine *) cmdline;
+
+  g_dbus_connection_call (gdbcl->connection,
+                          gdbcl->bus_name,
+                          gdbcl->object_path,
+                          "org.gtk.private.CommandLine", "Print",
+                          g_variant_new ("(s)", message),
+                          NULL, 0, -1, NULL, NULL, NULL);
+}
+
+static void
+g_dbus_command_line_printerr_literal (GApplicationCommandLine *cmdline,
+                                      const gchar             *message)
+{
+  GDBusCommandLine *gdbcl = (GDBusCommandLine *) cmdline;
+
+  g_dbus_connection_call (gdbcl->connection,
+                          gdbcl->bus_name,
+                          gdbcl->object_path,
+                          "org.gtk.private.CommandLine", "PrintError",
+                          g_variant_new ("(s)", message),
+                          NULL, 0, -1, NULL, NULL, NULL);
+}
+
+static void
+g_dbus_command_line_finalize (GObject *object)
+{
+  GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
+  GDBusCommandLine *gdbcl = (GDBusCommandLine *) object;
+  gint status;
+
+  status = g_application_command_line_get_exit_status (cmdline);
+
+  g_dbus_method_invocation_return_value (gdbcl->invocation,
+                                         g_variant_new ("(i)", status));
+  g_object_unref (gdbcl->invocation);
+
+  G_OBJECT_CLASS (g_dbus_command_line_parent_class)
+    ->finalize (object);
+}
+
+static void
+g_dbus_command_line_init (GDBusCommandLine *gdbcl)
+{
+}
+
+static void
+g_dbus_command_line_class_init (GApplicationCommandLineClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = g_dbus_command_line_finalize;
+  class->printerr_literal = g_dbus_command_line_printerr_literal;
+  class->print_literal = g_dbus_command_line_print_literal;
+}
+
+static GApplicationCommandLine *
+g_dbus_command_line_new (GDBusMethodInvocation *invocation)
+{
+  GDBusCommandLine *gdbcl;
+  GVariant *args;
+
+  args = g_dbus_method_invocation_get_parameters (invocation);
+
+  gdbcl = g_object_new (g_dbus_command_line_get_type (),
+                        "arguments", g_variant_get_child_value (args, 1),
+                        "platform-data", g_variant_get_child_value (args, 2),
+                        NULL);
+  gdbcl->connection = g_dbus_method_invocation_get_connection (invocation);
+  gdbcl->bus_name = g_dbus_method_invocation_get_sender (invocation);
+  g_variant_get_child (args, 0, "&o", &gdbcl->object_path);
+  gdbcl->invocation = g_object_ref (invocation);
+
+  return G_APPLICATION_COMMAND_LINE (gdbcl);
+}
diff --git a/gio/gapplicationimpl.h b/gio/gapplicationimpl.h
index 1bc5ec9..06a5320 100644
--- a/gio/gapplicationimpl.h
+++ b/gio/gapplicationimpl.h
@@ -25,4 +25,9 @@ void                    g_application_impl_open                         (GApplic
                                                                          GVariant           *platform_data);
 
 G_GNUC_INTERNAL
+int                     g_application_impl_command_line                 (GApplicationImpl   *impl,
+                                                                         GVariant           *arguments,
+                                                                         GVariant           *platform_data);
+
+G_GNUC_INTERNAL
 void                    g_application_impl_flush                        (GApplicationImpl   *impl);
diff --git a/gio/gio-marshal.list b/gio/gio-marshal.list
index 8b7ce0a..c6c3cae 100644
--- a/gio/gio-marshal.list
+++ b/gio/gio-marshal.list
@@ -23,3 +23,4 @@ VOID:STRING,STRING
 VOID:STRING,BOOLEAN
 VOID:POINTER,INT,STRING
 BOOLEAN:OBJECT
+INT:OBJECT
diff --git a/gio/gio.h b/gio/gio.h
index db1f13b..456e909 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -33,6 +33,7 @@
 #include <gio/gactiongroup.h>
 #include <gio/gsimpleactiongroup.h>
 #include <gio/gapplication.h>
+#include <gio/gapplicationcommandline.h>
 #include <gio/gasyncinitable.h>
 #include <gio/gasyncresult.h>
 #include <gio/gbufferedinputstream.h>
diff --git a/gio/gioenums.h b/gio/gioenums.h
index 5ebd7f0..98551cc 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1228,10 +1228,11 @@ typedef enum
 typedef enum
 {
   G_APPLICATION_FLAGS_NONE,
-  G_APPLICATION_FLAGS_IS_SERVICE  =          (1 << 0),
-  G_APPLICATION_FLAGS_IS_LAUNCHER =          (1 << 1),
+  G_APPLICATION_IS_SERVICE  =          (1 << 0),
+  G_APPLICATION_IS_LAUNCHER =          (1 << 1),
 
-  G_APPLICATION_FLAGS_HANDLES_OPEN =         (1 << 2)
+  G_APPLICATION_HANDLES_OPEN =         (1 << 2),
+  G_APPLICATION_HANDLES_COMMAND_LINE = (1 << 3)
 } GApplicationFlags;
 
 G_END_DECLS



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