[glib/wip/gapplication] Switch to a two-stage creation model
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gapplication] Switch to a two-stage creation model
- Date: Fri, 4 Jun 2010 21:03:05 +0000 (UTC)
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]