[glib/wip/gapplication] GApplication updates



commit e06fffc57cc7aa74f7d340e889754ee49a7ce92c
Author: Colin Walters <walters verbum org>
Date:   Fri May 28 16:44:04 2010 -0400

    GApplication updates
    
    * Port to latest GDBus API
    * Add GApplicationPlugin struct so subclasses can override
      lowlevel behavior
    * Require argc/argv in constructor
    * Add new "Activate" method which passes along argc/argv
      and any data gathered from plugin (GtkApplication will add
      startup notification, event timestamp)
    * Readd constructor which takes a subtype
    * Update tests

 gio/gapplication.c      |  148 +++++++++++++++++++++++++++++++++++++++++++----
 gio/gapplication.h      |   60 ++++++++++++++++---
 gio/gio-marshal.list    |    1 +
 gio/gunixapplication.c  |  132 ++++++++++++++++++++++++++++++-----------
 gio/tests/application.c |    2 +-
 gio/tests/testapp.c     |   16 +++++-
 gio/tests/testapps.c    |    3 +
 7 files changed, 304 insertions(+), 58 deletions(-)
---
diff --git a/gio/gapplication.c b/gio/gapplication.c
index 2713dd2..78b74c5 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -73,6 +73,7 @@ enum
 {
   QUIT,
   ACTION,
+  ACTIVATED,
 
   LAST_SIGNAL
 };
@@ -97,20 +98,30 @@ struct _GApplicationPrivate
   guint actions_changed_id;
 
 #ifdef G_OS_UNIX
+  char *dbus_path;
   GDBusConnection *session_bus;
 #endif
 };
 
-GApplication *primary_application = NULL;
+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);
+static void     _g_application_platform_init                    (GApplication  *app,
+								 const char    *appid);
 static gboolean _g_application_platform_acquire_single_instance (const char    *appid,
                                                                  GError       **error);
 static void     _g_application_platform_remote_invoke_action    (GApplication  *app,
                                                                  const char    *action,
                                                                  guint          timestamp);
-static void     _g_application_platform_default_quit            (void) G_GNUC_NORETURN;
+static void     _g_application_platform_activate                (const char    *appid,
+								 GVariant      *data) G_GNUC_NORETURN;
 static void     _g_application_platform_on_actions_changed      (GApplication  *app);
 
 #ifdef G_OS_UNIX
@@ -180,6 +191,36 @@ g_application_default_run (GApplication *application)
   g_main_loop_run (application->priv->mainloop);
 }
 
+static void
+_g_application_handle_activation (const char *appid)
+{
+  GVariantBuilder builder;
+  GVariant *message;
+  int i;
+  GApplicationConstructionData *construct_data;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("(asa{sv})"));
+  g_variant_builder_open (&builder, G_VARIANT_TYPE ("as"));
+
+  construct_data = g_static_private_get (&construction_data);
+  if (construct_data)
+    {
+      for (i = 1; i < construct_data->argc; i++)
+	g_variant_builder_add_value (&builder,
+				     g_variant_new_string (construct_data->argv[i]));
+    }
+  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);
+
+  message = g_variant_builder_end (&builder);
+  _g_application_platform_activate (appid, message);
+  g_variant_unref (message);
+}
+
 static gboolean
 timeout_handle_actions_changed (gpointer user_data)
 {
@@ -218,6 +259,8 @@ 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
@@ -230,12 +273,64 @@ g_application_action_free (gpointer data)
  * action.
  *
  * Returns: (transfer full): An application instance
+ *
+ * Since: 2.26
+ */
+GApplication *
+g_application_new (int                argc,
+		   char             **argv,
+		   const char        *appid)
+{
+  GApplication *app;
+  GApplicationConstructionData construct_data;
+
+  g_type_init ();
+
+  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;
+}
+
+/**
+ * g_application_new_subtype:
+ * @argc: Argument vector length
+ * @argv: (allow-none): Argument vector
+ * @appid: System-dependent application identifier
+ * @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:
  */
 GApplication *
-g_application_new (const char        *appid)
+g_application_new_subtype  (int                       argc,
+			    char                    **argv,
+			    const char               *appid,
+			    GType                     subtype,
+			    const GApplicationPlugin *plugin)
 {
+  GApplication *app;
+  GApplicationConstructionData construct_data;
+
   g_type_init ();
-  return g_object_new (G_TYPE_APPLICATION, "appid", appid, NULL);
+
+  construct_data.argc = argc;
+  construct_data.argv = argv;
+  construct_data.plugin = plugin;
+
+  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;
 }
 
 
@@ -546,6 +641,8 @@ g_application_quit (GApplication *application,
  * 
  * Returns: (transfer none): The primary instance of #GApplication,
  *   or %NULL if none is set
+ *
+ * Since: 2.26
  */
 GApplication *
 g_application_get_instance (void)
@@ -597,7 +694,6 @@ g_application_init (GApplication *app)
                                               NULL,
                                               g_application_action_free);
   app->priv->default_quit = TRUE;
-  _g_application_platform_init (app);
 }
 
 static void
@@ -682,11 +778,11 @@ g_application_constructor  (GType                  type,
   if (!_g_application_platform_acquire_single_instance (appid, NULL))
     {
       if (default_quit)
-        _g_application_platform_default_quit ();
+	_g_application_handle_activation (appid);
       else
         is_remote = TRUE;
     }
- 
+
   app = application_for_appid (appid);
   if (app != NULL)
     return g_object_ref (app);
@@ -700,8 +796,10 @@ g_application_constructor  (GType                  type,
   if (primary_application == NULL)
     primary_application = app;
   g_hash_table_insert (instances_for_appid, g_strdup (appid), app);
-  
-  return object; 
+
+  _g_application_platform_init (app, appid);
+
+  return object;
 }
 
 static void
@@ -737,8 +835,34 @@ g_application_class_init (GApplicationClass *klass)
                   _gio_marshal_VOID__STRING_INT,
                   G_TYPE_NONE, 2,
                   G_TYPE_STRING,
-                  G_TYPE_INT); 
- 
+                  G_TYPE_INT);
+
+   /**
+   * GApplication::activated:
+   * @args: Arguments given to non-primary process
+   * @data: Additional platform-specific data
+   *
+   * 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 given arguments are defined to be in UTF-8 encoding.
+   *
+   * There are no predefined contents included with @data; it will
+   * typically be used by #GApplication subclasses which will insert
+   * (for example) window system data.
+   */
+
+  application_signals[ACTIVATED] =
+    g_signal_new (g_intern_static_string ("activated"),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GApplicationClass, activated),
+                  NULL, NULL,
+                  _gio_marshal_VOID__BOXED_BOXED,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_STRV,
+		  G_TYPE_VARIANT);
+
    /**
    * GApplication:appid:
    *
diff --git a/gio/gapplication.h b/gio/gapplication.h
index 768ff6f..67d269c 100644
--- a/gio/gapplication.h
+++ b/gio/gapplication.h
@@ -43,6 +43,7 @@ G_BEGIN_DECLS
 typedef struct _GApplication            GApplication;
 typedef struct _GApplicationPrivate     GApplicationPrivate;
 typedef struct _GApplicationClass       GApplicationClass;
+typedef struct _GApplicationPlugin      GApplicationPlugin;
 
 /**
  * GApplication:
@@ -78,14 +79,17 @@ struct _GApplicationClass
 
   /*< public >*/
   /* signals */
-  void     (* action) (GApplication *application,
-                       const gchar  *action_name,
-                       guint         timestamp);
-  gboolean (* quit)   (GApplication *application,
-                       guint         timestamp);
-  
+  void        (* action) (GApplication *application,
+			  const gchar  *action_name,
+			  guint         timestamp);
+  gboolean    (* quit)   (GApplication *application,
+			  guint         timestamp);
+  void        (* activated)   (GApplication  *application,
+			       const gchar  **arguments,
+			       GVariant      *data);
+
   /* vfuncs */
-  void     (* run)    (GApplication *application);
+  void        (* run)    (GApplication *application);
 
   /*< private >*/
   /* Padding for future expansion */
@@ -97,9 +101,49 @@ struct _GApplicationClass
   void (*_g_reserved6) (void);
 };
 
+/**
+ * GApplicationPlugin:
+ *
+ * The #GApplicationPlugin structure allows subclasses of
+ * #GApplication to influence low-level behavior.  This
+ * should generally not be used by application authors.
+ *
+ * @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.
+ *
+ * Since: 2.26
+ */
+struct _GApplicationPlugin
+{
+  /*< public >*/
+  void (*format_activation_data) (GVariantBuilder *builder);
+
+  /*< 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                       (const char        *appid);
+GApplication *          g_application_new                       (int                       argc,
+								 char                    **argv,
+								 const char               *appid);
+
+GApplication *          g_application_new_subtype               (int                       argc,
+								 char                    **argv,
+								 const char               *appid,
+								 GType                     subtype,
+								 const GApplicationPlugin *plugin);
 
 GApplication *          g_application_get_instance              (void);
 G_CONST_RETURN gchar *  g_application_get_id                    (GApplication      *application);
diff --git a/gio/gio-marshal.list b/gio/gio-marshal.list
index 8924e40..2170173 100644
--- a/gio/gio-marshal.list
+++ b/gio/gio-marshal.list
@@ -11,3 +11,4 @@ VOID:BOOL,BOXED
 VOID:BOXED,BOXED
 VOID:INT
 VOID:STRING,INT
+VOID:BOXED,BOXED
diff --git a/gio/gunixapplication.c b/gio/gunixapplication.c
index 49eadc0..8e15188 100644
--- a/gio/gunixapplication.c
+++ b/gio/gunixapplication.c
@@ -29,7 +29,7 @@
 #include "gdbusintrospection.h"
 #include "gdbusmethodinvocation.h"
 
-#define G_APPLICATION_PATH "/org/gtk/Application"
+#define G_APPLICATION_PATH_PREFIX "/org/gtk/Application"
 #define G_APPLICATION_IFACE "org.gtk.Application"
 
 static void
@@ -100,6 +100,18 @@ application_dbus_method_call (GDBusConnection       *connection,
       
       g_dbus_method_invocation_return_value (invocation, NULL);
     }
+  else if (strcmp (method_name, "Activate") == 0)
+    {
+      GVariant *platform_data;
+      char **args;
+
+      g_variant_get (parameters, "(^a&s a{sv})", &args, &platform_data);
+      g_signal_emit (app, application_signals[ACTIVATED], 0, args, platform_data);
+      g_free (args);
+      g_variant_unref (platform_data);
+
+      g_dbus_method_invocation_return_value (invocation, NULL);
+    }
 }
 
 static const GDBusArgInfo application_quit_in_args[] =
@@ -181,11 +193,43 @@ static const GDBusMethodInfo application_invoke_action_method_info =
   NULL
 };
 
+static const GDBusArgInfo application_activate_in_args[] =
+{
+  {
+    -1,
+    "arguments",
+    "as",
+    NULL
+  },
+  {
+    -1,
+    "data",
+    "a{sv}",
+    NULL
+  }
+};
+
+static const GDBusArgInfo * const application_activate_in_args_p[] = {
+  &application_activate_in_args[0],
+  &application_activate_in_args[1],
+  NULL
+};
+
+static const GDBusMethodInfo application_activate_method_info =
+{
+  -1,
+  "Activate",
+  (GDBusArgInfo **) &application_activate_in_args_p,
+  NULL,
+  NULL
+};
+
 static const GDBusMethodInfo * const application_dbus_method_info_p[] =
 {
   &application_quit_method_info,
   &application_list_actions_method_info,
   &application_invoke_action_method_info,
+  &application_activate_method_info,
   NULL
 };
 
@@ -220,41 +264,38 @@ static GDBusInterfaceVTable application_dbus_vtable =
   NULL
 };
 
-static void
-_g_application_platform_init (GApplication *app)
+static char *
+application_path_from_appid (const char *appid)
 {
-  GApplicationPrivate *priv = app->priv;
-  GError *error = NULL;
-  guint registration_id;
   char *appid_path, *iter;
-  
-  priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-  if (priv->session_bus == NULL)
-    {
-      if (error != NULL)
-        {
-          g_warning ("Failed to connect to the session bus: %s", error->message);
-          g_clear_error (&error);
-        }
-      else
-        g_warning ("Failed to connect to the session bus");
 
-      return;
-    }
-
-  appid_path = g_strconcat (G_APPLICATION_PATH, app->priv->appid, NULL);
-  for (iter = appid_path + strlen (G_APPLICATION_PATH); *iter; iter++)
+  appid_path = g_strconcat (G_APPLICATION_PATH_PREFIX, "/", appid, NULL);
+  for (iter = appid_path + strlen (G_APPLICATION_PATH_PREFIX); *iter; iter++)
     {
       if (*iter == '.')
 	*iter = '/';
     }
-    
-  registration_id = g_dbus_connection_register_object (priv->session_bus, appid_path,
-                                                       &application_dbus_interface_info,
-                                                       &application_dbus_vtable,
-                                                       app, NULL,
-                                                       &error);
-  g_free (appid_path);
+
+  return appid_path;
+}
+
+static void
+_g_application_platform_init (GApplication *app,
+			      const char   *appid)
+{
+  GError *error = NULL;
+  guint registration_id;
+
+  app->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+  if (app->priv->session_bus == NULL)
+    g_error ("%s", error->message);
+
+  app->priv->dbus_path = application_path_from_appid (appid);
+  registration_id = g_dbus_connection_register_object (app->priv->session_bus, app->priv->dbus_path,
+						       &application_dbus_interface_info,
+						       &application_dbus_vtable,
+						       app, NULL,
+						       &error);
   if (registration_id == 0)
     g_error ("%s", error->message);
 }
@@ -278,8 +319,7 @@ _g_application_platform_acquire_single_instance (const char   *appid,
                                                 "org.freedesktop.DBus",
                                                 "RequestName",
                                                 g_variant_new ("(su)", appid, 0x4),
-                                                0, -1, NULL,
-                                                error);
+						NULL, 0, -1, NULL, error);
   if (request_result == NULL)
     return FALSE;
 
@@ -306,7 +346,7 @@ static void
 _g_application_platform_on_actions_changed (GApplication *app)
 {
   g_dbus_connection_emit_signal (app->priv->session_bus, NULL,
-                                 G_APPLICATION_PATH,
+				 app->priv->dbus_path,
                                  G_APPLICATION_IFACE,
                                  "ActionsChanged", NULL, NULL);
 }
@@ -319,18 +359,38 @@ _g_application_platform_remote_invoke_action (GApplication  *app,
   GVariant *result;
   result = g_dbus_connection_call_sync (app->priv->session_bus,
                                         app->priv->appid,
-                                        G_APPLICATION_PATH,
+                                        app->priv->dbus_path,
                                         G_APPLICATION_IFACE,
                                         "InvokeAction",
                                         g_variant_new ("(su)",
                                                        action,
                                                        timestamp),
-                                        0, -1, NULL, NULL);
-  g_variant_unref (result);
+					NULL, 0, -1, NULL, NULL);
+  if (result)
+    g_variant_unref (result);
 }
 
 static void
-_g_application_platform_default_quit (void)
+_g_application_platform_activate (const char *appid, GVariant *data)
 {
+  GVariant *result;
+  GDBusConnection *connection;
+  char *dbus_path;
+
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+  if (connection == NULL)
+    exit (0);
+
+  dbus_path = application_path_from_appid (appid);
+  result = g_dbus_connection_call_sync (connection,
+                                        appid,
+                                        dbus_path,
+                                        G_APPLICATION_IFACE,
+                                        "Activate",
+                                        data,
+                                        NULL, 0, -1, NULL, NULL);
+  g_free (dbus_path);
+  if (result)
+    g_variant_unref (result);
   exit (0);
 }
diff --git a/gio/tests/application.c b/gio/tests/application.c
index 7acd520..d779628 100644
--- a/gio/tests/application.c
+++ b/gio/tests/application.c
@@ -108,7 +108,7 @@ test_basic (void)
 {
   GApplication *app;
 
-  app = g_application_new ("org.gtk.TestApplication");
+  app = g_application_new (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 4a26f50..5534268 100644
--- a/gio/tests/testapp.c
+++ b/gio/tests/testapp.c
@@ -32,6 +32,18 @@ invoke_action1 (gpointer data)
   return FALSE;
 }
 
+static void
+on_app_activated (GApplication  *application,
+		  char         **args,
+		  GVariant      *platform_data)
+{
+  char **iter;
+  g_print ("got args: ");
+  for (iter = args; *iter; iter++)
+    g_print ("%s ", *iter);
+  g_print ("\n");
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -49,7 +61,7 @@ main (int argc, char *argv[])
     }
   else
     {
-      app = g_application_new ("org.gtk.test.app");
+      app = g_application_new (argc, argv, "org.gtk.test.app");
     }
 
   if (g_application_is_remote (app))
@@ -64,6 +76,8 @@ 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_CALLBACK (on_app_activated), NULL);
       g_application_run (app);
     }
 
diff --git a/gio/tests/testapps.c b/gio/tests/testapps.c
index 89d21b0..5cecfd6 100644
--- a/gio/tests/testapps.c
+++ b/gio/tests/testapps.c
@@ -133,6 +133,7 @@ quit_app (gpointer data)
                                      "org.gtk.Application",
                                      "Quit",
                                      g_variant_new ("(u)", 0),
+				     NULL,
                                      G_DBUS_CALL_FLAGS_NONE,
                                      -1,
                                      NULL,
@@ -238,6 +239,7 @@ list_actions (void)
                                      "org.gtk.Application",
                                      "ListActions",
                                      NULL,
+				     NULL,
                                      G_DBUS_CALL_FLAGS_NONE,
                                      -1,
                                      NULL,
@@ -319,6 +321,7 @@ invoke_action (gpointer data)
                                      g_variant_new ("(su)",
                                                     action,
                                                     0),
+				     NULL,
                                      G_DBUS_CALL_FLAGS_NONE,
                                      -1,
                                      NULL,



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