[glib/wip/gapplication] Switch to a two-stage creation model



commit de1510109f3523093d507c351e2e61cc3fdea610
Author: Colin Walters <walters verbum org>
Date:   Fri Jun 4 20:54:14 2010 -0400

    Switch to a two-stage creation model

 gio/gapplication.c      |  226 +++++++++++++++++++++--------------------------
 gio/gapplication.h      |   66 ++++----------
 gio/gdbusapplication.c  |   11 +--
 gio/gio.symbols         |    3 +-
 gio/tests/application.c |    2 +-
 gio/tests/testapp.c     |   46 +++-------
 6 files changed, 141 insertions(+), 213 deletions(-)
---
diff --git a/gio/gapplication.c b/gio/gapplication.c
index 78e50f8..bd22fd7 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -150,7 +150,7 @@ enum
 {
   QUIT,
   ACTION,
-  ACTIVATED,
+  PREPARE_ACTIVATION,
 
   LAST_SIGNAL
 };
@@ -182,18 +182,10 @@ struct _GApplicationPrivate
 #endif
 };
 
-typedef struct {
-  const GApplicationPlugin *plugin;
-  int argc;
-  char **argv;
-} GApplicationConstructionData;
-
-static GStaticPrivate construction_data = G_STATIC_PRIVATE_INIT;
 static GApplication *primary_application = NULL;
 static GHashTable *instances_for_appid = NULL;
 
-static void     _g_application_platform_init                    (GApplication  *app,
-                                                                 const char    *appid);
+static void     _g_application_platform_init                    (GApplication  *app); 
 static gboolean _g_application_platform_acquire_single_instance (const char    *appid,
                                                                  GError       **error);
 static void     _g_application_platform_remote_invoke_action    (GApplication  *app,
@@ -271,39 +263,40 @@ g_application_default_run (GApplication *application)
 }
 
 static void
-_g_application_handle_activation (const char *appid)
+_g_application_handle_activation (const char *appid,
+				  int         argc,
+				  char      **argv,
+				  GVariant   *platform_data)
 {
   GVariantBuilder builder;
   GVariant *message;
   int i;
-  GApplicationConstructionData *construct_data;
 
   g_variant_builder_init (&builder, G_VARIANT_TYPE ("(aaya{sv})"));
   g_variant_builder_open (&builder, G_VARIANT_TYPE ("aay"));
 
-  construct_data = g_static_private_get (&construction_data);
-  if (construct_data)
+  for (i = 1; i < argc; i++)
     {
-      for (i = 1; i < construct_data->argc; i++)
-        {
-          int j;
-          guint8 *argv_bytes;
-
-          g_variant_builder_open (&builder, G_VARIANT_TYPE ("ay"));
-
-          argv_bytes = (guint8*) construct_data->argv[i];
-          for (j = 0; argv_bytes[j]; j++)
-            g_variant_builder_add_value (&builder,
-                                         g_variant_new_byte (argv_bytes[j]));
+      int j;
+      guint8 *argv_bytes;
+      
+      g_variant_builder_open (&builder, G_VARIANT_TYPE ("ay"));
+      
+      argv_bytes = (guint8*) argv[i];
+      for (j = 0; argv_bytes[j]; j++)
+	g_variant_builder_add_value (&builder,
+				     g_variant_new_byte (argv_bytes[j]));
           g_variant_builder_close (&builder);
-        }
     }
   g_variant_builder_close (&builder);
 
-  g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
-  if (construct_data && construct_data->plugin)
-    construct_data->plugin->format_activation_data (&builder);
-  g_variant_builder_close (&builder);
+  if (platform_data)
+    g_variant_builder_add (&builder, "@a{sv}", platform_data);
+  else
+    {
+      g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
+      g_variant_builder_close (&builder);
+    }
 
   message = g_variant_builder_end (&builder);
   _g_application_platform_activate (appid, message);
@@ -348,85 +341,91 @@ g_application_action_free (gpointer data)
 
 /**
  * g_application_new:
- * @argc: Argument vector length
- * @argv: (allow-none): Argument vector
  * @appid: System-dependent application identifier
  *
- * Create a new #GApplication, or if one has already been initialized
- * for the given @appid, return the existing instance.  If the
- * application is already running in another process, this function
- * will initiate an platform-specific action such as bringing any
- * graphics windows associated with the application to the foreground.
+ * Create a new #GApplication.  The application is initially in
+ * "remote" mode.  Almost certainly, you want to call
+ * g_application_register() immediately after this function, which
+ * will finish initialization.
  *
- * This function is defined to call g_type_init() as its very first
- * action.
+ * As a convenience, this function is defined to call g_type_init() as
+ * its very first action.
  *
  * Returns: (transfer full): An application instance
  *
  * Since: 2.26
  */
 GApplication *
-g_application_new (int          argc,
-                   char       **argv,
-                   const char  *appid)
+g_application_new (const char  *appid)
 {
-  GApplication *app;
-  GApplicationConstructionData construct_data;
-
   g_type_init ();
 
-  /* We do this thread-local variable trick to avoid having to make
-   * argc and argv properties of the object.  It keeps the API
-   * slightly cleaner.
-   */
-  construct_data.argc = argc;
-  construct_data.argv = argv;
-  construct_data.plugin = NULL;
-
-  g_static_private_set (&construction_data, &construct_data, NULL);
-  app = g_object_new (G_TYPE_APPLICATION, "appid", appid, NULL);
-  g_static_private_set (&construction_data, NULL, NULL);
-  return app;
+  return G_APPLICATION (g_object_new (G_TYPE_APPLICATION, "appid", appid, NULL));
 }
 
 /**
- * g_application_new_subtype:
- * @argc: Argument vector length
- * @argv: (allow-none): Argument vector
- * @appid: System-dependent application identifier
- * @subtype: The type of the subclass to instantiate
- * @plugin: Structure containing callbacks for subclasses to override behavior
- *
- * This function is similar to g_application_new(), but includes a
- * @plugin which is intended for use only by subclasses of #GApplication.
- *
- * Returns: (transfer full): An application instance
- *
- * Since: 2.26
- * Skip:
+ * g_application_register:
+ * @application: A #GApplication
+ * @argc: System argument count
+ * @argv: (array length=argc): System argument vector 
+ * @platform_data: (allow-none): Arbitrary platform-specific data, must have signature "a{sv}"
+ * 
+ * Ensure the current process is the unique owner of the application.
+ * If successful, the GApplication:is-remote property will be changed
+ * to %FALSE, and it is safe to continue creating other resources
+ * such as graphics windows.
+ *
+ * If the given @appid is already running in another process, the
+ * #GApplication:default-exit property will be evaluated.  If it's
+ * %TRUE, then a platform-specific action such as bringing any
+ * graphics windows associated with the application to the foreground
+ * may be initiated.  After that, the current process will terminate.
+ * If %FALSE, then the application remains in the GApplication:is-remote
+ * state, and you can e.g. call g_application_invoke_action().
  */
-GApplication *
-g_application_new_subtype  (int                        argc,
-                            char                     **argv,
-                            const char                *appid,
-                            GType                      subtype,
-                            const GApplicationPlugin  *plugin)
+void
+g_application_register_with_data (GApplication      *application,
+				  int                argc,
+				  char             **argv,
+				  GVariant          *platform_data)
 {
-  GApplication *app;
-  GApplicationConstructionData construct_data;
+  g_return_if_fail (application->priv->appid == NULL);
+  g_return_if_fail (application->priv->is_remote);
+  g_return_if_fail (platform_data == NULL
+		    || strcmp (g_variant_get_type_string (platform_data), "a{sv}") == 0);
 
-  g_type_init ();
+  if (!_g_application_platform_acquire_single_instance (application->priv->appid, NULL))
+    {
+      if (application->priv->default_quit)
+        _g_application_handle_activation (application->priv->appid,
+					  argc, argv, platform_data);
+      else
+	return;
+    }
 
-  construct_data.argc = argc;
-  construct_data.argv = argv;
-  construct_data.plugin = plugin;
+  application->priv->is_remote = FALSE;
 
-  g_static_private_set (&construction_data, &construct_data, NULL);
-  app = g_object_new (subtype, "appid", appid, NULL);
-  g_static_private_set (&construction_data, NULL, NULL);
-  return app;
+  _g_application_platform_init (application);
 }
 
+/**
+ * g_application_new_and_register:
+ * @appid: An application identifier
+ * @argc: System argument count
+ * @argv: (array length=argc): System argument vector 
+ * 
+ * This is a convenience function which combines g_application_new()
+ * with g_application_register_with_data().
+ */
+GApplication *
+g_application_new_and_register (const char        *appid,
+				int                argc,
+				char             **argv)
+{
+  GApplication *app = g_application_new (appid);
+  g_application_register_with_data (app, argc, argv, NULL);
+  return app;
+}
 
 /**
  * g_application_add_action:
@@ -788,6 +787,7 @@ g_application_init (GApplication *app)
                                               NULL,
                                               g_application_action_free);
   app->priv->default_quit = TRUE;
+  app->priv->is_remote = TRUE;
 }
 
 static void
@@ -848,56 +848,31 @@ g_application_constructor  (GType                  type,
 {
   GApplication *app;
   GObject *object;
-  guint i;
   const char *appid = NULL;
-  gboolean default_quit = TRUE;
-  gboolean is_remote;
-  const GApplicationConstructionData *construct_data;
+  guint i;
 
   for (i = 0; i < n_construct_properties; i++)
     {
       GObjectConstructParam *param = &construct_params[i];
       if (strcmp (param->pspec->name, "appid") == 0)
         appid = g_value_get_string (param->value);
-      else if (strcmp (param->pspec->name, "default-quit") == 0)
-        default_quit = g_value_get_boolean (param->value);
     }
 
-  if (appid == NULL)
-    {
-      g_error ("Missing mandatory \"appid\" parameter for GApplication constructor");
-      return NULL;
-    }
-
-  is_remote = FALSE;
-  if (!_g_application_platform_acquire_single_instance (appid, NULL))
-    {
-      if (default_quit)
-        _g_application_handle_activation (appid);
-      else
-        is_remote = TRUE;
-    }
+  g_return_val_if_fail (appid != NULL, NULL);
 
   app = application_for_appid (appid);
   if (app != NULL)
     return g_object_ref (app);
-  
+
   object = (* G_OBJECT_CLASS (g_application_parent_class)->constructor) (type,
                                                                          n_construct_properties,
                                                                          construct_params);
   app = G_APPLICATION (object);
-  app->priv->is_remote = is_remote;
-
-  construct_data = g_static_private_get (&construction_data);
-  if (construct_data)
-    app->priv->plugin = construct_data->plugin;
 
   if (primary_application == NULL)
     primary_application = app;
   g_hash_table_insert (instances_for_appid, g_strdup (appid), app);
 
-  _g_application_platform_init (app, appid);
-
   return object;
 }
 
@@ -937,25 +912,28 @@ g_application_class_init (GApplicationClass *klass)
                   G_TYPE_INT);
 
    /**
-   * GApplication::activated:
+   * GApplication::prepare-activation:
    * @arguments: A #GVariant with the signature "aay"
+   * @platform_data: A #GVariant with the signature "a{sv}"
    *
    * This signal is emitted when a non-primary process for a given
    * application is invoked while your application is running; for
    * example, when a file browser launches your program to open a
    * file.  The raw operating system arguments are passed in the
-   * @arguments variant.  
+   * @arguments variant.  Additional platform-dependent data is
+   * stored in @platform_data.
    */
 
-  application_signals[ACTIVATED] =
-    g_signal_new (g_intern_static_string ("activated"),
+  application_signals[PREPARE_ACTIVATION] =
+    g_signal_new (g_intern_static_string ("prepare-activation"),
                   G_OBJECT_CLASS_TYPE (klass),
                   G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GApplicationClass, activated),
+                  G_STRUCT_OFFSET (GApplicationClass, prepare_activation),
                   NULL, NULL,
-                  g_cclosure_marshal_VOID__BOXED,
-                  G_TYPE_NONE, 1,
-                  G_TYPE_VARIANT);
+                  _gio_marshal_VOID__BOXED_BOXED,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_VARIANT,
+		  G_TYPE_VARIANT);
 
    /**
    * GApplication:appid:
@@ -1005,7 +983,7 @@ g_application_class_init (GApplicationClass *klass)
                                    g_param_spec_boolean ("is-remote",
                                                          P_("Is Remote"),
                                                          P_("Whether this application is a proxy for another process"),
-                                                         FALSE,
+                                                         TRUE,
                                                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
diff --git a/gio/gapplication.h b/gio/gapplication.h
index 73126db..96de514 100644
--- a/gio/gapplication.h
+++ b/gio/gapplication.h
@@ -84,11 +84,14 @@ struct _GApplicationClass
 			  guint         timestamp);
   gboolean    (* quit)   (GApplication *application,
 			  guint         timestamp);
-  void        (* activated)   (GApplication  *application,
-			       GVariant      *arguments);
+  void        (* prepare_activation)   (GApplication  *application,
+					GVariant      *arguments,
+					GVariant      *platform_data);
 
   /* vfuncs */
   void        (* run)    (GApplication *application);
+  void        (*format_activation_data) (GApplication    *application,
+					 GVariantBuilder *builder);
 
   /*< private >*/
   /* Padding for future expansion */
@@ -99,54 +102,18 @@ struct _GApplicationClass
   void (*_g_reserved5) (void);
   void (*_g_reserved6) (void);
 };
-
-/**
- * GApplicationPlugin:
- * @format_activation_data: Invoked when another process for this
- *     application exists.  The callback will be invoked in the context of
- *     the non-primary process.  This allows environmental data such as
- *     windowing system event data to be sent to the primary process.
- *     Handlers for this signal should assume @builder has been opened for
- *     an "a{sv}" type, and thus only append "sv" elements.
- * @receive_activation_data: Invoked when a non-primary process for
- *     this application is invoked.  This callback is invoked in the
- *     context of the primary process, and will be passed environmental
- *     data gathered from the @format_activation_data callback.
- *
- * The <structname>GApplicationPlugin</structname> structure allows
- * subclasses of #GApplication to influence low-level behavior.
- * This should generally not be used by application authors.
- *
- * Since: 2.26
- */
-struct _GApplicationPlugin
-{
-  /*< public >*/
-  void (*format_activation_data) (GVariantBuilder *builder);
-  void (*receive_activation_data) (GVariant *data);
-
-  /*< private >*/
-  /* Padding for future expansion */
-  void (*_g_reserved1) (void);
-  void (*_g_reserved2) (void);
-  void (*_g_reserved3) (void);
-  void (*_g_reserved4) (void);
-  void (*_g_reserved5) (void);
-  void (*_g_reserved6) (void);
-  void (*_g_reserved7) (void);
-};
-
 GType                   g_application_get_type                  (void) G_GNUC_CONST;
 
-GApplication *          g_application_new                       (int                       argc,
-								 char                    **argv,
-								 const char               *appid);
+GApplication *          g_application_new                       (const char               *appid);
+
+void                    g_application_register_with_data        (GApplication      *application,
+								 int                argc,
+								 char             **argv,
+								 GVariant          *platform_data);
 
-GApplication *          g_application_new_subtype               (int                       argc,
-								 char                    **argv,
-								 const char               *appid,
-								 GType                     subtype,
-								 const GApplicationPlugin *plugin);
+GApplication *          g_application_new_and_register           (const char       *appid,
+								  int               argc,
+								  char            **argv);
 
 GApplication *          g_application_get_instance              (void);
 G_CONST_RETURN gchar *  g_application_get_id                    (GApplication      *application);
@@ -173,6 +140,11 @@ gboolean                g_application_quit                      (GApplication
                                                                  guint              timestamp);
 
 gboolean                g_application_is_remote                 (GApplication      *application);
+
+void                    g_application_format_activation_data    (GApplication      *app,
+                                                                 GVariantBuilder   *builder);
+
+
 G_END_DECLS
 
 #endif /* __G_APPLICATION_H__ */
diff --git a/gio/gdbusapplication.c b/gio/gdbusapplication.c
index de9f522..b18e8a5 100644
--- a/gio/gdbusapplication.c
+++ b/gio/gdbusapplication.c
@@ -106,11 +106,7 @@ application_dbus_method_call (GDBusConnection       *connection,
 
       g_variant_get (parameters, "(@aay a{sv})", &args, &platform_data);
 
-      if (app->priv->plugin && app->priv->plugin->receive_activation_data)
-	{
-	  app->priv->plugin->receive_activation_data (platform_data);
-	}
-      g_signal_emit (app, application_signals[ACTIVATED], 0, args);
+      g_signal_emit (app, application_signals[PREPARE_ACTIVATION], 0, args, platform_data);
 
       g_variant_unref (args);
       g_variant_unref (platform_data);
@@ -286,8 +282,7 @@ application_path_from_appid (const char *appid)
 }
 
 static void
-_g_application_platform_init (GApplication *app,
-			      const char   *appid)
+_g_application_platform_init (GApplication *app)
 {
   GError *error = NULL;
   guint registration_id;
@@ -296,7 +291,7 @@ _g_application_platform_init (GApplication *app,
   if (app->priv->session_bus == NULL)
     g_error ("%s", error->message);
 
-  app->priv->dbus_path = application_path_from_appid (appid);
+  app->priv->dbus_path = application_path_from_appid (app->priv->appid);
   registration_id = g_dbus_connection_register_object (app->priv->session_bus, app->priv->dbus_path,
 						       &application_dbus_interface_info,
 						       &application_dbus_vtable,
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 17e5a60..2c31a72 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -30,7 +30,7 @@ g_vfs_get_local
 #if IN_FILE(__G_APPLICATION_C__)
 g_application_get_type G_GNUC_CONST
 g_application_new
-g_application_new_subtype
+g_application_new_and_register
 g_application_get_instance
 g_application_get_id
 g_application_set_action_enabled
@@ -38,6 +38,7 @@ g_application_get_action_enabled
 g_application_get_action_description
 g_application_add_action
 g_application_remove_action
+g_application_register_with_data
 g_application_invoke_action
 g_application_list_actions
 g_application_run
diff --git a/gio/tests/application.c b/gio/tests/application.c
index d779628..e44dbb0 100644
--- a/gio/tests/application.c
+++ b/gio/tests/application.c
@@ -108,7 +108,7 @@ test_basic (void)
 {
   GApplication *app;
 
-  app = g_application_new (0, NULL, "org.gtk.TestApplication");
+  app = g_application_new_and_register (0, NULL, "org.gtk.TestApplication");
   g_application_add_action (app, "About", "Print an about message");
 
   g_signal_connect (app, "action::About", G_CALLBACK (on_app_action), NULL);
diff --git a/gio/tests/testapp.c b/gio/tests/testapp.c
index b42543a..0e1ca4e 100644
--- a/gio/tests/testapp.c
+++ b/gio/tests/testapp.c
@@ -34,28 +34,20 @@ invoke_action1 (gpointer data)
 
 static void
 on_app_activated (GApplication  *application,
-		  GVariant      *args)
+		  GVariant      *args,
+		  GVariant      *platform_data)
 {
   GVariantIter iter;
   GVariant *arg;
-  g_print ("got args: ");
-  
-  g_variant_iter_init (&iter, args);
-  while (g_variant_iter_next (&iter, "@ay", &arg))
-    {
-      const guint8 *bytes;
-      gsize len;
-      char *utf;
+  char *str;
 
-      bytes = g_variant_get_byte_array (arg, &len);
-      utf = g_locale_to_utf8 ((char*) bytes, len, NULL, NULL, NULL);
-      
-      if (utf)
-	g_print ("%s ", utf);
-      g_free (utf);
-      g_variant_unref (arg);
-    }
-  g_print ("\n");
+  g_print ("got args: ");
+  str = g_variant_print (args, TRUE);
+  g_print ("%s ", str);
+  g_free (str);
+  str = g_variant_print (platform_data, TRUE);
+  g_print ("%s\n", str);
+  g_free (str);
 }
 
 int
@@ -64,19 +56,9 @@ main (int argc, char *argv[])
   GApplication *app;
   GMainLoop *loop;
 
-  if (argc > 1 && strcmp (argv[1], "--non-unique") == 0)
-    {
-      g_type_init ();
-
-      app = g_object_new (G_TYPE_APPLICATION,
-                          "appid", "org.gtk.test.app",
-                          "default-quit", FALSE,
-                          NULL);
-    }
-  else
-    {
-      app = g_application_new (argc, argv, "org.gtk.test.app");
-    }
+  app = g_application_new ("org.gtk.test.app");
+  if (!(argc > 1 && strcmp (argv[1], "--non-unique") == 0))
+    g_application_register_with_data (app, argc, argv, NULL);
 
   if (g_application_is_remote (app))
     {
@@ -90,7 +72,7 @@ main (int argc, char *argv[])
       g_application_add_action (app, "action2", "Action2");
       g_signal_connect (app, "action",
                         G_CALLBACK (on_app_action), NULL);
-      g_signal_connect (app, "activated",
+      g_signal_connect (app, "prepare-activation",
                         G_CALLBACK (on_app_activated), NULL);
       g_application_run (app);
     }



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