[gnome-terminal] Port to GDBus



commit fdf01b94d14d7f9c4df7e9f762f851d0800c4927
Author: Christian Persch <chpe gnome org>
Date:   Sat May 8 18:08:48 2010 +0200

    Port to GDBus
    
    ... and remove dbus-glib dependency.

 configure.ac                     |   16 +-
 src/Makefile.am                  |    9 -
 src/terminal-app.c               |   71 +++-
 src/terminal-app.h               |    5 +-
 src/terminal-factory-service.xml |   11 -
 src/terminal-util.c              |  138 --------
 src/terminal-util.h              |   12 -
 src/terminal.c                   |  682 +++++++++++++++++++-------------------
 8 files changed, 399 insertions(+), 545 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 4ab16e3..da58eef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 m4_define([gt_version_major],[2])
 m4_define([gt_version_minor],[31])
 m4_define([gt_version_micro],[3])
-m4_define([gt_version_extra],[git])
+m4_define([gt_version_extra],[-git])
 m4_define([gt_version],[gt_version_major().gt_version_minor().gt_version_micro()gt_version_extra])
 
 m4_define([gt_api_version],[0])
@@ -39,10 +39,10 @@ GNOME_COMPILE_WARNINGS([maximum])
 
 AM_GLIB_GNU_GETTEXT
 
-GLIB_REQUIRED=2.16.0
+GLIB_REQUIRED=2.25.0
+GIO_REQUIRED=2.25.4
 GTK_REQUIRED=2.14.0
-GCONF_REQUIRED=2.14.0
-DBUS_GLIB_REQUIRED=0.6
+GCONF_REQUIRED=2.31.3
 VTE_REQUIRED=0.25.1
 
 AC_MSG_CHECKING([which gtk+ version to compile against])
@@ -75,10 +75,9 @@ PKG_CHECK_MODULES([TERM],
   [vte >= $VTE_REQUIRED
    glib-2.0 >= $GLIB_REQUIRED
    gthread-2.0
-   gio-2.0
+   gio-2.0 >= $GIO_REQUIRED
    gtk+-$GTK_API_VERSION >= $GTK_REQUIRED
    gconf-2.0 >= $GCONF_REQUIRED
-   dbus-glib-1 >= $DBUS_GLIB_REQUIRED
    $PLATFORM_DEPS])
 
 # Check the smclient backend
@@ -128,11 +127,6 @@ if test "$GTK_BUILDER_CONVERT" = "false"; then
   AC_MSG_ERROR([gtk-builder-convert not found])
 fi
 
-AC_PATH_PROG([DBUS_BINDING_TOOL],[dbus-binding-tool],[false])
-if test "$DBUS_BINDING_TOOL" = "false"; then
-  AC_MSG_ERROR([dbus-binding-tool not found])
-fi
-
 GNOME_DOC_INIT
 
 # ****************************
diff --git a/src/Makefile.am b/src/Makefile.am
index bad5a38..c05e85f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,8 +5,6 @@ SUBDIRS = skey
 bin_PROGRAMS = gnome-terminal
 
 BUILT_SOURCES = \
-	terminal-factory-client.h \
-	terminal-factory-server.h \
 	terminal-marshal.c \
 	terminal-marshal.h \
 	terminal-type-builtins.c \
@@ -142,12 +140,6 @@ terminal-marshal.c: $(srcdir)/terminal-marshal.list
 		&& mv terminal-marshal.c.tmp terminal-marshal.c ) \
 	|| ( rm -f terminal-marshal.c.tmp && exit 1 )
 
-terminal-factory-client.h: terminal-factory-service.xml
-	$(AM_V_GEN) $(DBUS_BINDING_TOOL) --mode=glib-client --output=$@ $<
-
-terminal-factory-server.h: terminal-factory-service.xml
-	$(AM_V_GEN) $(DBUS_BINDING_TOOL) --mode=glib-server --prefix=terminal_factory --output=$@ $<
-
 schemadir = $(GCONF_SCHEMA_FILE_DIR)
 schema_in_files = gnome-terminal.schemas.in
 schema_DATA = gnome-terminal.schemas
@@ -183,7 +175,6 @@ CLEANFILES = \
 	$(BUILT_SOURCES)
 
 EXTRA_DIST = \
-	terminal-factory-service.xml \
 	terminal-marshal.list \
 	terminal-type-builtins.c.template \
 	terminal-type-builtins.h.template \
diff --git a/src/terminal-app.c b/src/terminal-app.c
index 39ea6bc..30592f4 100644
--- a/src/terminal-app.c
+++ b/src/terminal-app.c
@@ -43,6 +43,9 @@
 
 #ifdef WITH_SMCLIENT
 #include "eggsmclient.h"
+#ifdef GDK_WINDOWING_X11
+#include "eggdesktopfile.h"
+#endif
 #endif
 
 #define FALLBACK_PROFILE_ID "Default"
@@ -109,8 +112,6 @@ struct _TerminalApp
   PangoFontDescription *system_font_desc;
   gboolean enable_mnemonics;
   gboolean enable_menu_accels;
-
-  gboolean use_factory;
 };
 
 enum
@@ -146,6 +147,9 @@ enum
 
 static TerminalApp *global_app = NULL;
 
+/* Evil hack alert: this is exported from libgconf-2 but not in a public header */
+extern gboolean gconf_spawn_daemon(GError** err);
+
 #define MONOSPACE_FONT_DIR "/desktop/gnome/interface"
 #define MONOSPACE_FONT_KEY MONOSPACE_FONT_DIR "/monospace_font_name"
 #define DEFAULT_MONOSPACE_FONT ("Monospace 10")
@@ -1380,8 +1384,26 @@ G_DEFINE_TYPE (TerminalApp, terminal_app, G_TYPE_OBJECT)
 static void
 terminal_app_init (TerminalApp *app)
 {
+  GError *error = NULL;
+
   global_app = app;
 
+  /* If the gconf daemon isn't available (e.g. because there's no dbus
+   * session bus running), we'd crash later on. Tell the user about it
+   * now, and exit. See bug #561663.
+   * Don't use gconf_ping_daemon() here since the server may just not
+   * be running yet, but able to be started. See comments on bug #564649.
+   */
+  if (!gconf_spawn_daemon (&error))
+    {
+      g_printerr ("Failed to summon the GConf demon; exiting.  %s\n", error->message);
+      g_error_free (error);
+
+      exit (EXIT_FAILURE);
+    }
+
+  gtk_window_set_default_icon_name (GNOME_TERMINAL_ICON_NAME);
+
   /* Initialise defaults */
   app->enable_mnemonics = DEFAULT_ENABLE_MNEMONICS;
   app->enable_menu_accels = DEFAULT_ENABLE_MENU_BAR_ACCEL;
@@ -1457,6 +1479,16 @@ terminal_app_init (TerminalApp *app)
 #ifdef WITH_SMCLIENT
 {
   EggSMClient *sm_client;
+#ifdef GDK_WINDOWING_X11
+  char *desktop_file;
+
+  desktop_file = g_build_filename (TERM_DATADIR,
+                                   "applications",
+                                   PACKAGE ".desktop",
+                                   NULL);
+  egg_set_desktop_file_without_defaults (desktop_file);
+  g_free (desktop_file);
+#endif /* GDK_WINDOWING_X11 */
 
   sm_client = egg_sm_client_get ();
   g_signal_connect (sm_client, "save-state",
@@ -1572,6 +1604,12 @@ terminal_app_set_property (GObject *object,
 }
 
 static void
+terminal_app_real_quit (TerminalApp *app)
+{
+  gtk_main_quit();
+}
+
+static void
 terminal_app_class_init (TerminalAppClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -1580,6 +1618,8 @@ terminal_app_class_init (TerminalAppClass *klass)
   object_class->get_property = terminal_app_get_property;
   object_class->set_property = terminal_app_set_property;
 
+  klass->quit = terminal_app_real_quit;
+
   signals[QUIT] =
     g_signal_new (I_("quit"),
                   G_OBJECT_CLASS_TYPE (object_class),
@@ -1638,31 +1678,27 @@ terminal_app_class_init (TerminalAppClass *klass)
 
 /* Public API */
 
-void
-terminal_app_initialize (gboolean use_factory)
+TerminalApp*
+terminal_app_get (void)
 {
-  g_assert (global_app == NULL);
-  g_object_new (TERMINAL_TYPE_APP, NULL);
-  g_assert (global_app != NULL);
+  if (global_app == NULL) {
+    g_object_new (TERMINAL_TYPE_APP, NULL);
+    g_assert (global_app != NULL);
+  }
 
-  global_app->use_factory = use_factory;
+  return global_app;
 }
 
 void
 terminal_app_shutdown (void)
 {
-  g_assert (global_app != NULL);
+  if (global_app == NULL)
+    return;
+
   g_object_unref (global_app);
   g_assert (global_app == NULL);
 }
 
-TerminalApp*
-terminal_app_get (void)
-{
-  g_assert (global_app != NULL);
-  return global_app;
-}
-
 /**
  * terminal_app_handle_options:
  * @app:
@@ -2025,9 +2061,6 @@ terminal_app_save_config (TerminalApp *app,
   g_key_file_set_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_VERSION, TERMINAL_CONFIG_VERSION);
   g_key_file_set_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_COMPAT_VERSION, TERMINAL_CONFIG_COMPAT_VERSION);
 
-  /* FIXMEchpe this seems useless */
-  g_key_file_set_boolean (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_FACTORY, app->use_factory);
-
   window_names_array = g_ptr_array_sized_new (g_list_length (app->windows) + 1);
 
   for (lw = app->windows; lw != NULL; lw = lw->next)
diff --git a/src/terminal-app.h b/src/terminal-app.h
index 300d91a..4dda51d 100644
--- a/src/terminal-app.h
+++ b/src/terminal-app.h
@@ -34,7 +34,6 @@ G_BEGIN_DECLS
 #define TERMINAL_CONFIG_COMPAT_VERSION      (1) /* Bump this for incompatible changes */
 
 #define TERMINAL_CONFIG_GROUP               "GNOME Terminal Configuration"
-#define TERMINAL_CONFIG_PROP_FACTORY        "FactoryEnabled"
 #define TERMINAL_CONFIG_PROP_VERSION        "Version"
 #define TERMINAL_CONFIG_PROP_COMPAT_VERSION "CompatVersion"
 #define TERMINAL_CONFIG_PROP_WINDOWS        "Windows"
@@ -83,12 +82,10 @@ typedef struct _TerminalApp TerminalApp;
 
 GType terminal_app_get_type (void);
 
-void terminal_app_initialize (gboolean use_factory);
+TerminalApp* terminal_app_get (void);
 
 void terminal_app_shutdown (void);
 
-TerminalApp* terminal_app_get (void);
-
 gboolean terminal_app_handle_options (TerminalApp *app,
                                       TerminalOptions *options,
                                       gboolean allow_resume,
diff --git a/src/terminal-util.c b/src/terminal-util.c
index 5ed9d2a..ddb9499 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -514,144 +514,6 @@ terminal_util_key_file_get_argv (GKeyFile *key_file,
   return NULL;
 }
 
-/* Why? Because dbus-glib sucks, that's why! */
-
-/**
- * terminal_util_string_to_array:
- * @string:
- *
- * Converts the string @string into a #GArray.
- * 
- * Returns: a newly allocated #GArray containing @string's bytes.
- */
-GArray *
-terminal_util_string_to_array (const char *string)
-{
-  GArray *array;
-  gsize len = 0;
-
-  if (string)
-    len = strlen (string);
-
-  array = g_array_sized_new (FALSE, FALSE, sizeof (guchar), len);
-  return g_array_append_vals (array, string, len);
-}
-
-/**
- * terminal_util_strv_to_array:
- * @argc: the length of @argv
- * @argv: a string array
- *
- * Converts the string array @argv of length @argc into a #GArray.
- * 
- * Returns: a newly allocated #GArray
- */
-GArray *
-terminal_util_strv_to_array (int argc,
-                             char **argv)
-{
-  GArray *array;
-  gsize len = 0;
-  int i;
-  const char nullbyte = 0;
-
-  for (i = 0; i < argc; ++i)
-    len += strlen (argv[i]);
-  if (argc > 0)
-    len += argc - 1;
-
-  array = g_array_sized_new (FALSE, FALSE, sizeof (guchar), len);
-
-  for (i = 0; i < argc; ++i) {
-    g_array_append_vals (array, argv[i], strlen (argv[i]));
-    if (i < argc)
-      g_array_append_val (array, nullbyte);
-  }
-
-  return array;
-}
-
-/**
- * terminal_util_array_to_string:
- * @array:
- * @error: a #GError to fill in
- *
- * Converts @array into a string.
- * 
- * Returns: a newly allocated string, or %NULL on error
- */
-char *
-terminal_util_array_to_string (const GArray *array,
-                               GError **error)
-{
-  char *string;
-  g_return_val_if_fail (array != NULL, NULL);
-
-  string = g_strndup (array->data, array->len);
-
-  /* Validate */
-  if (strlen (string) < array->len) {
-    g_set_error_literal (error,
-                         g_quark_from_static_string ("terminal-error"),
-                         0,
-                         "String is shorter than claimed");
-    return NULL;
-  }
-
-  return string;
-}
-
-/**
- * terminal_util_array_to_strv:
- * @array:
- * @argc: a location to store the length of the returned string array
- * @error: a #GError to fill in
- *
- * Converts @array into a string.
- * 
- * Returns: a newly allocated string array of length * argc, or %NULL on error
- */
-char **
-terminal_util_array_to_strv (const GArray *array,
-                             int *argc,
-                             GError **error)
-{
-  GPtrArray *argv;
-  const char *data, *nullbyte;
-  gssize len;
-
-  g_return_val_if_fail (array != NULL, NULL);
-
-  if (array->len == 0 || array->len > G_MAXSSIZE) {
-    *argc = 0;
-    return NULL;
-  }
-
-  argv = g_ptr_array_new ();
-
-  len = array->len;
-  data = array->data;
-
-  do {
-    gsize string_len;
-
-    nullbyte = memchr (data, '\0', len);
-
-    string_len = nullbyte ? (gsize) (nullbyte - data) : len;
-    g_ptr_array_add (argv, g_strndup (data, string_len));
-
-    len -= string_len + 1;
-    data += string_len + 1;
-  } while (len > 0);
-
-  if (argc)
-    *argc = argv->len;
-
-  /* NULL terminate */
-  g_ptr_array_add (argv, NULL);
-  return (char **) g_ptr_array_free (argv, FALSE);
-}
-
 /* Proxy stuff */
 
 static char *
diff --git a/src/terminal-util.h b/src/terminal-util.h
index a705fc7..66f8b79 100644
--- a/src/terminal-util.h
+++ b/src/terminal-util.h
@@ -87,18 +87,6 @@ char **terminal_util_key_file_get_argv    (GKeyFile *key_file,
                                            int *argc,
                                            GError **error);
 
-GArray *terminal_util_string_to_array (const char *string);
-
-GArray *terminal_util_strv_to_array (int argc,
-                                     char **argv);
-
-char *terminal_util_array_to_string (const GArray *array,
-                                     GError **error);
-
-char **terminal_util_array_to_strv (const GArray *array,
-                                    int *argc,
-                                    GError **error);
-
 void terminal_util_add_proxy_env (GHashTable *env_table);
 
 typedef enum {
diff --git a/src/terminal.c b/src/terminal.c
index 8160635..70d0a0b 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -29,19 +29,13 @@
 
 #include <glib.h>
 #include <glib/gstdio.h>
+#include <gio/gio.h>
 
 #include <gdk/gdkx.h>
 
 #ifdef WITH_SMCLIENT
 #include "eggsmclient.h"
-#ifdef GDK_WINDOWING_X11
-#include "eggdesktopfile.h"
 #endif
-#endif
-
-#include <dbus/dbus-protocol.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
 
 #include "terminal-accels.h"
 #include "terminal-app.h"
@@ -54,54 +48,314 @@
 #define TERMINAL_FACTORY_SERVICE_PATH         "/org/gnome/Terminal/Factory"
 #define TERMINAL_FACTORY_INTERFACE_NAME       "org.gnome.Terminal.Factory"
 
-#define TERMINAL_TYPE_FACTORY             (terminal_factory_get_type ())
-#define TERMINAL_FACTORY(object)          (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_FACTORY, TerminalFactory))
-#define TERMINAL_FACTORY_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_FACTORY, TerminalFactoryClass))
-#define TERMINAL_IS_FACTORY(object)       (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_FACTORY))
-#define TERMINAL_IS_FACTORY_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_FACTORY))
-#define TERMINAL_FACTORY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_FACTORY, TerminalFactoryClass))
+/* The returned string is owned by @variant */
+static const char *
+ay_to_string (GVariant *variant,
+              GError **error)
+{
+  const char *string;
+  gsize len;
+
+  string = g_variant_get_byte_array (variant, &len);
+  if (len == 0)
+    return NULL;
+
+  /* Validate that the string is nul-terminated and full-length */
+  if (string[len - 1] != '\0') {
+    g_set_error_literal (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                         "String not nul-terminated!");
+    return NULL;
+  }
+  if (strlen (string) != (len - 1)) {
+    g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                         "String is shorter than claimed (claimed %" G_GSIZE_FORMAT " actual %" G_GSIZE_FORMAT ")",
+                         len, strlen (string));
+    return NULL;
+  }
 
-typedef struct _TerminalFactory        TerminalFactory;
-typedef struct _TerminalFactoryClass   TerminalFactoryClass;
-typedef struct _TerminalFactoryPrivate TerminalFactoryPrivate;
+  return string;
+}
 
-struct _TerminalFactory
+/* The returned strings are owned by @variant. Free the array itself with g_free(). */
+static char **
+aay_to_strv (GVariant *variant,
+             int *argc,
+             GError **error)
 {
-  GObject parent_instance;
-};
+  GVariant *item;
+  char **argv;
+  gsize i, n;
+
+  n = g_variant_n_children (variant);
+  if (argc)
+    *argc = n;
+  if (n == 0)
+    return NULL;
+
+  argv = g_new (char *, n + 1);
+
+  for (i = 0; i < n; ++i) {
+    item = g_variant_get_child_value (variant, i);
+    argv[i] = (char *) ay_to_string (item, error);
+    g_variant_unref (item);
+    if (*error != NULL)
+      goto err;
+  }
+
+  argv[n] = NULL;
+  return argv;
+
+err:
+  g_free (argv);
+  return NULL;
+}
 
-struct _TerminalFactoryClass
+typedef struct {
+  char *factory_name;
+  TerminalOptions *options;
+  int exit_code;
+  char **argv;
+  int argc;
+} OwnData;
+
+static void
+method_call_cb (GDBusConnection *connection,
+                const char *sender,
+                const char *object_path,
+                const char *interface_name,
+                const char *method_name,
+                GVariant *parameters,
+                GDBusMethodInvocation *invocation,
+                gpointer user_data)
 {
-  GObjectClass parent_class;
-};
-
-static gboolean
-terminal_factory_handle_arguments (TerminalFactory *factory,
-                                   const GArray *working_directory_array,
-                                   const GArray *display_name_array,
-                                   const GArray *startup_id_array,
-                                   const GArray *argv_array,
-                                   const GArray *env_array,
-                                   GError **error);
-
-#include "terminal-factory-client.h"
-#include "terminal-factory-server.h"
-
-static GType terminal_factory_get_type (void);
-
-G_DEFINE_TYPE_WITH_CODE (TerminalFactory, terminal_factory, G_TYPE_OBJECT,
-  dbus_g_object_type_install_info (g_define_type_id,
-                                   &dbus_glib_terminal_factory_object_info)
-);
+  if (g_strcmp0 (method_name, "HandleArguments") == 0) {
+    TerminalOptions *options = NULL;
+    GVariant *v_wd, *v_display, *v_sid, *v_envv, *v_argv;
+    const char *working_directory = NULL, *display_name = NULL, *startup_id = NULL;
+    char **envv = NULL, **argv = NULL;
+    int argc;
+    GError *error = NULL;
+
+    g_variant_get (parameters, "(@ay ay@ay aay@aay)",
+                   &v_wd, &v_display, &v_sid, &v_envv, &v_argv);
+
+    working_directory = ay_to_string (v_wd, &error);
+    if (error)
+      goto out;
+    display_name = ay_to_string (v_display, &error);
+    if (error)
+      goto out;
+    startup_id = ay_to_string (v_sid, &error);
+    if (error)
+      goto out;
+    envv = aay_to_strv (v_envv, NULL, &error);
+    if (error)
+      goto out;
+    argv = aay_to_strv (v_argv, &argc, &error);
+    if (error)
+      goto out;
+
+    _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+                          "Factory invoked with working-dir='%s' display='%s' startup-id='%s'\n",
+                          working_directory ? working_directory : "(null)",
+                          display_name ? display_name : "(null)",
+                          startup_id ? startup_id : "(null)");
+
+    options = terminal_options_parse (working_directory,
+                                      display_name,
+                                      startup_id,
+                                      envv,
+                                      TRUE,
+                                      TRUE,
+                                      &argc, &argv,
+                                      &error,
+                                      NULL);
+
+    if (options != NULL) {
+      terminal_app_handle_options (terminal_app_get (), options, FALSE /* no resume */, &error);
+      terminal_options_free (options);
+    }
  
+  out:
+    g_variant_unref (v_wd);
+    g_variant_unref (v_display);
+    g_variant_unref (v_sid);
+    g_free (envv);
+    g_variant_unref (v_envv);
+    g_free (argv);
+    g_variant_unref (v_argv);
+
+    if (error == NULL) {
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+    } else {
+      g_dbus_method_invocation_return_gerror (invocation, error);
+      g_error_free (error);
+    }
+  }
+}
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+                 const char *name,
+                 gpointer user_data)
+{
+  static const char dbus_introspection_xml[] =
+    "<node name='/org/gnome/Terminal'>"
+      "<interface name='org.gnome.Terminal.Factory'>"
+        "<method name='HandleArguments'>"
+          "<arg type='ay' name='working_directory' direction='in' />"
+          "<arg type='ay' name='display_name' direction='in' />"
+          "<arg type='ay' name='startup_id' direction='in' />"
+          "<arg type='aay' name='environment' direction='in' />"
+          "<arg type='aay' name='arguments' direction='in' />"
+        "</method>"
+      "</interface>"
+    "</node>";
+
+  static const GDBusInterfaceVTable interface_vtable = {
+    method_call_cb,
+    NULL,
+    NULL,
+  };
+
+  OwnData *data = (OwnData *) user_data;
+  GDBusNodeInfo *introspection_data;
+  guint registration_id;
+  GError *error = NULL;
+
+  _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+                         "Bus %s acquired\n", name);
+
+  introspection_data = g_dbus_node_info_new_for_xml (dbus_introspection_xml, NULL);
+  g_assert (introspection_data != NULL);
+
+  registration_id = g_dbus_connection_register_object (connection,
+                                                       TERMINAL_FACTORY_SERVICE_PATH,
+                                                       introspection_data->interfaces[0],
+                                                       &interface_vtable,
+                                                       introspection_data,
+                                                       (GDestroyNotify) g_dbus_node_info_unref,
+                                                       &error);
+  if (registration_id == 0) {
+    g_printerr ("Failed to register object: %s\n", error->message);
+    g_error_free (error);
+    data->exit_code = EXIT_FAILURE;
+    gtk_main_quit ();
+  }
+}
+
 static void
-terminal_factory_class_init (TerminalFactoryClass *factory_class)
+name_acquired_cb (GDBusConnection *connection,
+                  const char *name,
+                  gpointer user_data)
 {
+  OwnData *data = (OwnData *) user_data;
+  GError *error = NULL;
+
+  _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+                         "Acquired the name %s on the session bus\n", name);
+
+  if (data->options == NULL) {
+    /* Name re-acquired!? */
+    g_assert_not_reached ();
+  }
+
+
+  if (!terminal_app_handle_options (terminal_app_get (), data->options, FALSE /* no resume */, &error)) {
+    g_printerr ("Failed to handle options: %s\n", error->message);
+    g_error_free (error);
+    data->exit_code = EXIT_FAILURE;
+    gtk_main_quit ();
+  }
+
+  terminal_options_free (data->options);
+  data->options = NULL;
 }
 
 static void
-terminal_factory_init (TerminalFactory *factory)
+name_lost_cb (GDBusConnection *connection,
+              const char *name,
+              gpointer user_data)
 {
+  OwnData *data = (OwnData *) user_data;
+  GError *error = NULL;
+  char **envv;
+  int envc, i;
+  GVariantBuilder builder;
+  GVariant *value;
+
+  _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+                         "Lost the name %s on the session bus\n", name);
+
+  if (data->options == NULL) {
+    /* Already handled */
+    data->exit_code = EXIT_SUCCESS;
+    gtk_main_quit ();
+    return;
+  }
+
+  _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+                          "Forwarding arguments to existing instance\n");
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ayayayaayaay)"));
+
+  g_variant_builder_add (&builder, "@ay",
+                         g_variant_new_byte_array (data->options->default_working_dir ? data->options->default_working_dir : "", -1));
+  g_variant_builder_add (&builder, "@ay",
+                         g_variant_new_byte_array (data->options->display_name ? data->options->display_name : "", -1));
+  g_variant_builder_add (&builder, "@ay",
+                         g_variant_new_byte_array (data->options->startup_id ? data->options->startup_id : "", -1));
+
+  g_variant_builder_open (&builder, G_VARIANT_TYPE ("aay"));
+  envv = g_listenv ();
+  envc = g_strv_length (envv);
+  for (i = 0; i < envc; ++i)
+    {
+      const char *value;
+      char *str;
+
+      value = g_getenv (envv[i]);
+      if (value == NULL)
+        continue;
+
+      str = g_strdup_printf ("%s=%s", envv[i], value);
+      g_variant_builder_add (&builder, "@ay", g_variant_new_byte_array (str, -1));
+      g_free (str);
+    }
+  g_variant_builder_close (&builder);
+
+  g_variant_builder_open (&builder, G_VARIANT_TYPE ("aay"));
+  for (i = 0; i < data->argc; ++i)
+    g_variant_builder_add (&builder, "@ay",
+                           g_variant_new_byte_array (data->argv[i], -1));
+  g_variant_builder_close (&builder);
+
+  value = g_dbus_connection_call_sync (connection,
+                                       data->factory_name,
+                                       TERMINAL_FACTORY_SERVICE_PATH,
+                                       TERMINAL_FACTORY_INTERFACE_NAME,
+                                       "HandleArguments",
+                                       g_variant_builder_end (&builder),
+                                       G_VARIANT_TYPE ("()"),
+                                       G_DBUS_CALL_FLAGS_NONE,
+                                       -1,
+                                       NULL,
+                                       &error);
+  if (value == NULL) {
+    _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+                           "Failed to forward arguments: %s\n", error->message);
+    g_error_free (error);
+    data->exit_code = EXIT_FAILURE;
+    gtk_main_quit ();
+  } else {
+    g_variant_unref (value);
+    data->exit_code = EXIT_SUCCESS;
+  }
+
+  terminal_options_free (data->options);
+  data->options = NULL;
+
+  gtk_main_quit ();
 }
 
 /* Settings storage works as follows:
@@ -126,8 +380,6 @@ terminal_factory_init (TerminalFactory *factory)
  *
  */
 
-static TerminalFactory *factory = NULL;
-
 /* Copied from libnautilus/nautilus-program-choosing.c; Needed in case
  * we have no DESKTOP_STARTUP_ID (with its accompanying timestamp).
  */
@@ -179,39 +431,6 @@ slowly_and_stupidly_obtain_timestamp (Display *xdisplay)
   return event.xproperty.time;
 }
 
-static void
-about_url_hook (GtkAboutDialog *about,
-	        const char *uri,
-	        gpointer user_data)
-{
-  GError *error = NULL;
-
-  if (!gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (about)),
-                      uri,
-                      gtk_get_current_event_time (),
-                      &error))
-    {
-      terminal_util_show_error_dialog (GTK_WINDOW (about), NULL, error,
-                                       "%s", _("Could not open link"));
-      g_error_free (error);
-    }
-}
-
-static void
-about_email_hook (GtkAboutDialog *about,
-		  const char *email_address,
-		  gpointer user_data)
-{
-  char *escaped, *uri;
-
-  escaped = g_uri_escape_string (email_address, NULL, FALSE);
-  uri = g_strdup_printf ("mailto:%s";, escaped);
-  g_free (escaped);
-
-  about_url_hook (about, uri, user_data);
-  g_free (uri);
-}
-
 static char *
 get_factory_name_for_display (const char *display_name)
 {
@@ -235,24 +454,16 @@ get_factory_name_for_display (const char *display_name)
   return g_string_free (name, FALSE);
 }
 
-/* Evil hack alert: this is exported from libgconf-2 but not in a public header */
-extern gboolean gconf_spawn_daemon(GError** err);
-
 int
 main (int argc, char **argv)
 {
   int i;
   char **argv_copy;
   int argc_copy;
-  const char *startup_id, *display_name;
+  const char *startup_id, *display_name, *home_dir;
   GdkDisplay *display;
   TerminalOptions *options;
-  DBusGConnection *connection;
-  char *factory_name = NULL;
-  DBusGProxy *proxy;
-  guint32 request_name_ret;
   GError *error = NULL;
-  const char *home_dir;
   char *working_directory;
   int ret = EXIT_SUCCESS;
 
@@ -278,6 +489,14 @@ main (int argc, char **argv)
 
   working_directory = g_get_current_dir ();
 
+  /* Now change directory to $HOME so we don't prevent unmounting, e.g. if the
+   * factory is started by nautilus-open-terminal. See bug #565328.
+   * On failure back to /.
+   */
+  home_dir = g_get_home_dir ();
+  if (home_dir == NULL || chdir (home_dir) < 0)
+    (void) chdir ("/");
+
   options = terminal_options_parse (working_directory,
                                     NULL,
                                     startup_id,
@@ -294,12 +513,11 @@ main (int argc, char **argv)
 
   g_free (working_directory);
 
-  if (!options)
-    {
-      g_printerr (_("Failed to parse arguments: %s\n"), error->message);
-      g_error_free (error);
-      exit (1);
-    }
+  if (options == NULL) {
+    g_printerr (_("Failed to parse arguments: %s\n"), error->message);
+    g_error_free (error);
+    exit (EXIT_FAILURE);
+  }
 
   g_set_application_name (_("Terminal"));
   
@@ -324,268 +542,50 @@ main (int argc, char **argv)
   display_name = gdk_display_get_name (display);
   options->display_name = g_strdup (display_name);
   
-  if (!options->use_factory)
-    goto factory_disabled;
+  if (options->use_factory) {
+    OwnData *data;
+    guint owner_id;
 
-  /* Now try to acquire register us as the terminal factory */
-  connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
-  if (!connection)
-    {
-      g_printerr ("Failed to get the session bus: %s\nFalling back to non-factory mode.\n",
-                  error->message);
-      g_clear_error (&error);
-      goto factory_disabled;
-    }
+    data = g_new (OwnData, 1);
+    data->factory_name = get_factory_name_for_display (display_name);
+    data->options = options;
+    data->exit_code = -1;
+    data->argv = argv_copy;
+    data->argc = argc_copy;
 
-  proxy = dbus_g_proxy_new_for_name (connection,
-                                     DBUS_SERVICE_DBUS,
-                                     DBUS_PATH_DBUS,
-                                     DBUS_INTERFACE_DBUS);
-#if 0
-  dbus_g_proxy_add_signal (proxy, "NameOwnerChanged",
-                           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-                           G_TYPE_INVALID);
-  dbus_g_proxy_connect_signal (proxy, "NameOwnerChanged",
-                               G_CALLBACK (name_owner_changed), factory, NULL);
-#endif
+    owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                               data->factory_name,
+                               G_BUS_NAME_OWNER_FLAGS_NONE,
+                               bus_acquired_cb,
+                               name_acquired_cb,
+                               name_lost_cb,
+                               data, NULL);
 
-  factory_name = get_factory_name_for_display (display_name);
-  if (!org_freedesktop_DBus_request_name (proxy,
-                                          factory_name,
-                                          DBUS_NAME_FLAG_DO_NOT_QUEUE,
-                                          &request_name_ret,
-                                          &error))
-    {
-      g_printerr ("Failed name request: %s\n", error->message);
-      g_clear_error (&error);
-      goto factory_disabled;
-    }
+    gtk_main ();
 
-  /* Forward to the existing factory and exit */
-  if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
-    {
-      char **env;
-      const char *evalue;
-      GPtrArray *env_ptr_array;
-      int envc;
-      GArray *working_directory_array, *display_name_array, *startup_id_array;
-      GArray *env_array, *argv_array;
-      gboolean retval;
-
-      _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
-                             "Forwarding arguments to existing instance\n");
-
-      env = g_listenv ();
-      envc = g_strv_length (env);
-      env_ptr_array = g_ptr_array_sized_new (envc);
-      for (i = 0; i < envc; ++i)
-        {
-          evalue = g_getenv (env[i]);
-          if (evalue)
-            g_ptr_array_add (env_ptr_array, g_strdup_printf ("%s=%s", env[i], evalue));
-        }
-      g_ptr_array_add (env_ptr_array, NULL);
-
-      g_strfreev (env);
-      env = (char **) g_ptr_array_free (env_ptr_array, FALSE);
-
-      working_directory = g_get_current_dir ();
-      working_directory_array = terminal_util_string_to_array (working_directory);
-      display_name_array = terminal_util_string_to_array (options->display_name);
-      startup_id_array = terminal_util_string_to_array (options->startup_id);
-      env_array = terminal_util_strv_to_array (envc, env);
-      argv_array = terminal_util_strv_to_array (argc_copy, argv_copy);
-
-      proxy = dbus_g_proxy_new_for_name (connection,
-                                         factory_name,
-                                         TERMINAL_FACTORY_SERVICE_PATH,
-                                         TERMINAL_FACTORY_INTERFACE_NAME);
-      retval = org_gnome_Terminal_Factory_handle_arguments (proxy,
-                                                            working_directory_array,
-                                                            display_name_array,
-                                                            startup_id_array,
-                                                            env_array,
-                                                            argv_array,
-                                                            &error);
-      g_free (working_directory);
-      g_array_free (working_directory_array, TRUE);
-      g_array_free (display_name_array, TRUE);
-      g_array_free (startup_id_array, TRUE);
-      g_array_free (env_array, TRUE);
-      g_array_free (argv_array, TRUE);
-      g_strfreev (env);
-
-      if (!retval)
-        {
-          if (g_error_matches (error, DBUS_GERROR, DBUS_GERROR_UNKNOWN_METHOD))
-            {
-              /* Incompatible factory version, fall back, to new instance */
-              g_printerr (_("Incompatible factory version; creating a new instance.\n"));
-              g_clear_error (&error);
-
-              goto factory_disabled;
-            }
-
-          g_printerr (_("Factory error: %s\n"), error->message);
-          g_error_free (error);
-          ret = EXIT_FAILURE;
-        }
-
-      g_free (argv_copy);
-      terminal_options_free (options);
-
-      exit (ret);
-    }
-
-  factory = g_object_new (TERMINAL_TYPE_FACTORY, NULL);
-  dbus_g_connection_register_g_object (connection,
-                                       TERMINAL_FACTORY_SERVICE_PATH,
-                                       G_OBJECT (factory));
-
-  /* Now we're registered as the factory. Proceed to open the terminal(s). */
-
-factory_disabled:
-  g_free (argv_copy);
-  g_free (factory_name);
-
-  /* If the gconf daemon isn't available (e.g. because there's no dbus
-   * session bus running), we'd crash later on. Tell the user about it
-   * now, and exit. See bug #561663.
-   * Don't use gconf_ping_daemon() here since the server may just not
-   * be running yet, but able to be started. See comments on bug #564649.
-   */
-  if (!gconf_spawn_daemon (&error))
-    {
-      g_printerr ("Failed to summon the GConf demon; exiting.  %s\n", error->message);
-      g_error_free (error);
-      exit (1);
-    }
-
-  gtk_window_set_default_icon_name (GNOME_TERMINAL_ICON_NAME);
+    ret = data->exit_code;
+    g_bus_unown_name (owner_id);
 
-  gtk_about_dialog_set_url_hook (about_url_hook, NULL, NULL);
-  gtk_about_dialog_set_email_hook (about_email_hook, NULL, NULL);
-
-#if defined(WITH_SMCLIENT) && defined(GDK_WINDOWING_X11)
-  {
-    char *desktop_file;
-
-    desktop_file = g_build_filename (TERM_DATADIR,
-                                     "applications",
-                                     PACKAGE ".desktop",
-                                     NULL);
-    egg_set_desktop_file_without_defaults (desktop_file);
-    g_free (desktop_file);
-  }
-#endif
+    g_free (data->factory_name);
+    g_free (data);
 
-  terminal_app_initialize (options->use_factory);
-  g_signal_connect (terminal_app_get (), "quit", G_CALLBACK (gtk_main_quit), NULL);
+  } else {
 
-  terminal_app_handle_options (terminal_app_get (), options, TRUE /* allow resume */, &error);
-  terminal_options_free (options);
+    terminal_app_handle_options (terminal_app_get (), options, TRUE /* allow resume */, &error);
+    terminal_options_free (options);
 
-  if (error)
-    {
+    if (error == NULL) {
+      gtk_main ();
+    } else {
       g_printerr ("Error handling options: %s\n", error->message);
-      g_clear_error (&error);
-
+      g_error_free (error);
       ret = EXIT_FAILURE;
-      goto shutdown;
     }
-
-  /* Now change directory to $HOME so we don't prevent unmounting, e.g. if the
-   * factory is started by nautilus-open-terminal. See bug #565328.
-   * On failure back to /.
-   */
-  home_dir = g_get_home_dir ();
-  if (home_dir == NULL || chdir (home_dir) < 0)
-    (void) chdir ("/");
-
-  gtk_main ();
-
-shutdown:
+  }
 
   terminal_app_shutdown ();
 
-  if (factory)
-    g_object_unref (factory);
-
-  return ret;
-}
-
-/* Factory stuff */
-
-static gboolean
-terminal_factory_handle_arguments (TerminalFactory *terminal_factory,
-                                   const GArray *working_directory_array,
-                                   const GArray *display_name_array,
-                                   const GArray *startup_id_array,
-                                   const GArray *env_array,
-                                   const GArray *argv_array,
-                                   GError **error)
-{
-  TerminalOptions *options = NULL;
-  char *working_directory = NULL, *display_name = NULL, *startup_id = NULL;
-  char **env = NULL, **argv = NULL, **argv_copy = NULL;
-  int argc;
-  GError *arg_error = NULL;
-  gboolean retval;
-
-  working_directory = terminal_util_array_to_string (working_directory_array, &arg_error);
-  if (arg_error)
-    goto out;
-  display_name = terminal_util_array_to_string (display_name_array, &arg_error);
-  if (arg_error)
-    goto out;
-  startup_id = terminal_util_array_to_string (startup_id_array, &arg_error);
-  if (arg_error)
-    goto out;
-  env = terminal_util_array_to_strv (env_array, NULL, &arg_error);
-  if (arg_error)
-    goto out;
-  argv = terminal_util_array_to_strv (argv_array, &argc, &arg_error);
-  if (arg_error)
-    goto out;
-
-  _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
-                         "Factory invoked with working-dir='%s' display='%s' startup-id='%s'\n",
-                         working_directory ? working_directory : "(null)",
-                         display_name ? display_name : "(null)",
-                         startup_id ? startup_id : "(null)");
-
-  /* Copy the arguments since terminal_options_parse potentially modifies the array */
-  argv_copy = (char **) g_memdup (argv, (argc + 1) * sizeof (char *));
-
-  options = terminal_options_parse (working_directory,
-                                    display_name,
-                                    startup_id,
-                                    env,
-                                    TRUE,
-                                    TRUE,
-                                    &argc, &argv_copy,
-                                    error,
-                                    NULL);
-
-out:
-  g_free (working_directory);
-  g_free (display_name);
-  g_free (startup_id);
-  g_strfreev (env);
-  g_strfreev (argv);
   g_free (argv_copy);
 
-  if (arg_error)
-    {
-      g_propagate_error (error, arg_error);
-      return FALSE;
-    }
-
-  if (!options)
-    return FALSE;
-
-  retval = terminal_app_handle_options (terminal_app_get (), options, FALSE /* no resume */, error);
-
-  terminal_options_free (options);
-  return retval;
+  return ret;
 }



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