[glib/wip/gapplication] GApplication updates
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gapplication] GApplication updates
- Date: Fri, 28 May 2010 20:45:40 +0000 (UTC)
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]