diff options
Diffstat (limited to 'gio/gapplication.c')
-rw-r--r-- | gio/gapplication.c | 1058 |
1 files changed, 1058 insertions, 0 deletions
diff --git a/gio/gapplication.c b/gio/gapplication.c new file mode 100644 index 000000000..d974ed9fa --- /dev/null +++ b/gio/gapplication.c @@ -0,0 +1,1058 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2010 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Colin Walters <walters@verbum.org> + * Emmanuele Bassi <ebassi@linux.intel.com> + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> + +#include <gobject/gvaluecollector.h> + +#include "gapplication.h" +#include "gio-marshal.h" +#include "glibintl.h" + +#include "gioerror.h" + +#include "gdbusconnection.h" +#include "gdbusintrospection.h" +#include "gdbusmethodinvocation.h" + +#include "gioalias.h" + +/** + * SECTION: gapplication + * @title: GApplication + * @short_description: Core application class + * + * A #GApplication is the foundation of an application, unique for + * a given application identifier. The #GApplication wraps some + * low-level platform-specific services; it's expected that most + * software will use a higher-level application class such as + * #GtkApplication or #MxApplication. + * + * In addition to single-instance-ness, #GApplication provides support + * for 'actions', which can be presented to the user in a platform-specific + * way (e.g. Windows 7 jump lists). Note that these are just simple actions + * without parameters. For more flexible scriptability, implementing a + * a separate D-Bus interface is recommended, see e.g. + * <xref linkend="gdbus-convenience"/>. + * + * Before using #GApplication, you must choose an "application identifier". + * The expected form of an application identifier is very close to that of + * of a <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-interface">DBus bus name</ulink>. + * Examples include: "com.example.MyApp" "org.example.internal-apps.Calculator" + * For convenience, the restrictions on application identifiers are reproduced + * here: + * <itemizedlist> + * <listitem>Application identifiers must contain only the ASCII characters "[A-Z][a-z][0-9]_-" and must not begin with a digit.</listitem> + * <listitem>Application identifiers must contain at least one '.' (period) character (and thus at least two elements).</listitem> + * <listitem>Application identifiers must not begin with a '.' (period) character.</listitem> + * <listitem>Application identifiers must not exceed 255 characters.</listitem> + * </itemizedlist> + * + * <refsect2><title>D-Bus implementation</title> + * <para> + * On UNIX systems using D-Bus, #GApplication is implemented by claiming the + * application identifier as a bus name on the session bus. The implementation + * exports an object at the object path that is created by replacing '.' with + * '/' in the application identifier (e.g. the object path for the + * application id 'org.gtk.TestApp' is '/org/gtk/TestApp'). The object + * implements the org.gtk.Application interface. + * </para> + * <classsynopsis class="interface"> + * <ooclass><interfacename>org.gtk.Application</interfacename></ooclass> + * <methodsynopsis> + * <void/> + * <methodname>Activate</methodname> + * <methodparam><modifier>in</modifier><type>aay</type><parameter>arguments</parameter></methodparam> + * <methodparam><modifier>in</modifier><type>a{sv}</type><parameter>data</parameter></methodparam> + * </methodsynopsis> + * <methodsynopsis> + * <void/> + * <methodname>InvokeAction</methodname> + * <methodparam><modifier>in</modifier><type>s</type><parameter>action</parameter></methodparam> + * <methodparam><modifier>in</modifier><type>u</type><parameter>timestamp</parameter></methodparam> + * </methodsynopsis> + * <methodsynopsis> + * <type>a{s(sb)}</type> + * <methodname>ListActions</methodname> + * <void/> + * </methodsynopsis> + * <methodsynopsis> + * <void/> + * <methodname>Quit</methodname> + * <methodparam><modifier>in</modifier><type>u</type><parameter>timestamp</parameter></methodparam> + * </methodsynopsis> + * <methodsynopsis> + * <modifier>Signal</modifier> + * <void/> + * <methodname>ActionsChanged</methodname> + * <void/> + * </methodsynopsis> + * </classsynopsis> + * <para> + * The <methodname>Activate</methodname> function is called on the existing + * application instance when a second instance fails to take the bus name. + * @arguments contains the commandline arguments given to the second instance + * and @data contains platform-specific additional data, see + * g_application_format_activation_data(). + * </para> + * <para> + * The <methodname>InvokeAction</methodname> function can be called to invoke + * one of the actions exported by the application. The @timestamp parameter + * should be taken from the user event that triggered the method call (e.g. + * a button press event). + * </para> + * <para> + * The <methodname>ListActions</methodname> function returns a dictionary + * with the exported actions of the application. The keys of the dictionary + * are the action names, and the values are structs containing the description + * for the action and a boolean that represents if the action is enabled or not. + * </para> + * <para> + * The <methodname>Quit</methodname> function can be called to terminate + * the application. The @timestamp parameter should be taken from the user + * event that triggered the method call (e.g. a button press event). + * </para> + * <para> + * The <methodname>ActionsChanged</methodname> signal is emitted when the + * exported actions change (i.e. an action is added, removed, enabled, + * disabled, or otherwise changed). + * </para> + * </refsect2> + * + * Since: 2.24 + */ + +G_DEFINE_TYPE (GApplication, g_application, G_TYPE_OBJECT); + +enum +{ + PROP_0, + + PROP_APPID, + PROP_DEFAULT_QUIT, + PROP_IS_REMOTE +}; + +enum +{ + QUIT, + ACTION, + PREPARE_ACTIVATION, + + LAST_SIGNAL +}; + +static guint application_signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + char *name; + char *description; + guint enabled : 1; +} GApplicationAction; + +struct _GApplicationPrivate +{ + char *appid; + GHashTable *actions; /* name -> GApplicationAction */ + GMainLoop *mainloop; + + guint default_quit : 1; + guint is_remote : 1; + + guint actions_changed_id; + +#ifdef G_OS_UNIX + char *dbus_path; + GDBusConnection *session_bus; +#endif +}; + +static GApplication *primary_application = NULL; +static GHashTable *instances_for_appid = NULL; + +static void _g_application_platform_init (GApplication *app); +static gboolean _g_application_platform_acquire_single_instance (GApplication *app, + GError **error); +static void _g_application_platform_remote_invoke_action (GApplication *app, + const char *action, + guint timestamp); +static void _g_application_platform_remote_quit (GApplication *app, + guint timestamp); +static void _g_application_platform_activate (GApplication *app, + GVariant *data) G_GNUC_NORETURN; +static void _g_application_platform_on_actions_changed (GApplication *app); + +#ifdef G_OS_UNIX +#include "gdbusapplication.c" +#else +#include "gnullapplication.c" +#endif + +static gboolean +_g_application_validate_id (const char *id) +{ + gboolean allow_dot; + + if (strlen (id) > 255) + return FALSE; + + if (!g_ascii_isalpha (*id)) + return FALSE; + + id++; + allow_dot = FALSE; + for (; *id; id++) + { + if (g_ascii_isalnum (*id) || (*id == '-') || (*id == '_')) + allow_dot = TRUE; + else if (allow_dot && *id == '.') + allow_dot = FALSE; + else + return FALSE; + } + return TRUE; +} + +static gpointer +init_appid_statics (gpointer data) +{ + instances_for_appid = g_hash_table_new (g_str_hash, g_str_equal); + return NULL; +} + +static GApplication * +application_for_appid (const char *appid) +{ + static GOnce appid_once = G_ONCE_INIT; + + g_once (&appid_once, init_appid_statics, NULL); + + return g_hash_table_lookup (instances_for_appid, appid); +} + +static gboolean +g_application_default_quit (GApplication *application, + guint timestamp) +{ + g_return_val_if_fail (application->priv->mainloop != NULL, FALSE); + g_main_loop_quit (application->priv->mainloop); + + return TRUE; +} + +static void +g_application_default_run (GApplication *application) +{ + if (application->priv->mainloop == NULL) + application->priv->mainloop = g_main_loop_new (NULL, TRUE); + + g_main_loop_run (application->priv->mainloop); +} + +static void +_g_application_handle_activation (GApplication *app, + int argc, + char **argv, + GVariant *platform_data) +{ + GVariantBuilder builder; + GVariant *message; + int i; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("(aaya{sv})")); + g_variant_builder_open (&builder, G_VARIANT_TYPE ("aay")); + + for (i = 1; i < argc; i++) + { + 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); + + 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 (app, message); + g_variant_unref (message); +} + +static gboolean +timeout_handle_actions_changed (gpointer user_data) +{ + GApplication *application = user_data; + + application->priv->actions_changed_id = 0; + + _g_application_platform_on_actions_changed (application); + + return FALSE; +} + +static inline void +queue_actions_change_notification (GApplication *application) +{ + GApplicationPrivate *priv = application->priv; + + if (priv->actions_changed_id == 0) + priv->actions_changed_id = g_timeout_add (0, timeout_handle_actions_changed, application); +} + +static void +g_application_action_free (gpointer data) +{ + if (G_LIKELY (data != NULL)) + { + GApplicationAction *action = data; + + g_free (action->name); + g_free (action->description); + + g_slice_free (GApplicationAction, action); + } +} + + +/** + * g_application_new: + * @appid: System-dependent application identifier + * + * 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. + * + * 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 (const char *appid) +{ + g_type_init (); + + return G_APPLICATION (g_object_new (G_TYPE_APPLICATION, "appid", appid, NULL)); +} + +/** + * 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(). + */ +void +g_application_register_with_data (GApplication *application, + int argc, + char **argv, + GVariant *platform_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); + + if (!_g_application_platform_acquire_single_instance (application, NULL)) + { + if (application->priv->default_quit) + _g_application_handle_activation (application, argc, argv, platform_data); + else + return; + } + + application->priv->is_remote = FALSE; + + _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: + * @application: a #GApplication + * @name: the action name + * @description: the action description; can be a translatable + * string + * + * Adds an action @name to the list of exported actions of @application. + * + * It is an error to call this function if @application is a proxy for + * a remote application. + * + * You can invoke an action using g_application_invoke_action(). + * + * The newly added action is enabled by default; you can call + * g_application_set_action_enabled() to disable it. + * + * Since: 2.26 + */ +void +g_application_add_action (GApplication *application, + const gchar *name, + const gchar *description) +{ + GApplicationPrivate *priv; + GApplicationAction *action; + + g_return_if_fail (G_IS_APPLICATION (application)); + g_return_if_fail (name != NULL && *name != '\0'); + g_return_if_fail (!application->priv->is_remote); + + priv = application->priv; + + g_return_if_fail (g_hash_table_lookup (priv->actions, name) == NULL); + + action = g_slice_new (GApplicationAction); + action->name = g_strdup (name); + action->description = g_strdup (description); + action->enabled = TRUE; + + g_hash_table_insert (priv->actions, action->name, action); + queue_actions_change_notification (application); +} + +/** + * g_application_remove_action: + * @application: a #GApplication + * @name: the name of the action to remove + * + * Removes the action @name from the list of exported actions of @application. + * + * It is an error to call this function if @application is a proxy for + * a remote application. + * + * Since: 2.26 + */ +void +g_application_remove_action (GApplication *application, + const gchar *name) +{ + GApplicationPrivate *priv; + + g_return_if_fail (G_IS_APPLICATION (application)); + g_return_if_fail (name != NULL && *name != '\0'); + g_return_if_fail (!application->priv->is_remote); + + priv = application->priv; + + g_return_if_fail (g_hash_table_lookup (priv->actions, name) != NULL); + + g_hash_table_remove (priv->actions, name); + queue_actions_change_notification (application); +} + +/** + * g_application_invoke_action: + * @application: a #GApplication + * @name: the name of the action to invoke + * @timestamp: the timestamp that is going to be passed to + * the #GApplication::action signal + * + * Invokes the action @name of the passed #GApplication. + * + * This function has different behavior depending on whether @application + * is acting as a proxy for another process. In the normal case where + * the current process is hosting the application, and the specified + * action exists and is enabled, the #GApplication::action signal will + * be emitted. + * + * If @application is a proxy, then the specified action will be invoked + * in the remote process. It is not necessary to call + * g_application_add_action() in the current process in order to invoke + * one remotely. + * + * Since: 2.26 + */ +void +g_application_invoke_action (GApplication *application, + const char *name, + guint timestamp) +{ + GApplicationPrivate *priv; + GApplicationAction *action; + + g_return_if_fail (G_IS_APPLICATION (application)); + g_return_if_fail (name != NULL); + + priv = application->priv; + + if (priv->is_remote) + { + _g_application_platform_remote_invoke_action (application, name, timestamp); + return; + } + + action = g_hash_table_lookup (priv->actions, name); + g_return_if_fail (action != NULL); + if (!action->enabled) + return; + + g_signal_emit (application, application_signals[ACTION], + g_quark_from_string (name), + name, + timestamp); +} + +/** + * g_application_list_actions: + * @application: a #GApplication + * + * Retrieves the list of action names currently exported by @application. + * + * It is an error to call this function if @application is a proxy for + * a remote application. + * + * Return value: (transfer full): a newly allocation, %NULL-terminated array + * of strings containing action names; use g_strfreev() to free the + * resources used by the returned array + * + * Since: 2.26 + */ +gchar ** +g_application_list_actions (GApplication *application) +{ + GApplicationPrivate *priv; + GHashTableIter iter; + gpointer key; + gchar **retval; + gint i; + + g_return_val_if_fail (G_IS_APPLICATION (application), NULL); + g_return_val_if_fail (!application->priv->is_remote, NULL); + + priv = application->priv; + + retval = g_new (gchar*, g_hash_table_size (priv->actions)); + + i = 0; + g_hash_table_iter_init (&iter, priv->actions); + while (g_hash_table_iter_next (&iter, &key, NULL)) + retval[i++] = g_strdup (key); + + retval[i] = NULL; + + return retval; +} + +/** + * g_application_set_action_enabled: + * @application: a #GApplication + * @name: the name of the application + * @enabled: whether to enable or disable the action @name + * + * Sets whether the action @name inside @application should be enabled + * or disabled. + * + * It is an error to call this function if @application is a proxy for + * a remote application. + * + * Invoking a disabled action will not result in the #GApplication::action + * signal being emitted. + * + * Since: 2.26 + */ +void +g_application_set_action_enabled (GApplication *application, + const gchar *name, + gboolean enabled) +{ + GApplicationAction *action; + + g_return_if_fail (G_IS_APPLICATION (application)); + g_return_if_fail (name != NULL); + g_return_if_fail (!application->priv->is_remote); + + enabled = !!enabled; + + action = g_hash_table_lookup (application->priv->actions, name); + g_return_if_fail (action != NULL); + if (action->enabled == enabled) + return; + + action->enabled = enabled; + + queue_actions_change_notification (application); +} + + +/** + * g_application_get_action_description: + * @application: a #GApplication + * @name: Action name + * + * Gets the description of the action @name. + * + * It is an error to call this function if @application is a proxy for + * a remote application. + * + * Returns: Description for the given action named @name + * + * Since: 2.26 + */ +G_CONST_RETURN gchar * +g_application_get_action_description (GApplication *application, + const gchar *name) +{ + GApplicationAction *action; + + g_return_val_if_fail (G_IS_APPLICATION (application), NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (!application->priv->is_remote, NULL); + + action = g_hash_table_lookup (application->priv->actions, name); + g_return_val_if_fail (action != NULL, NULL); + + return action->description; +} + + +/** + * g_application_get_action_enabled: + * @application: a #GApplication + * @name: the name of the action + * + * Retrieves whether the action @name is enabled or not. + * + * See g_application_set_action_enabled(). + * + * It is an error to call this function if @application is a proxy for + * a remote application. + * + * Return value: %TRUE if the action was enabled, and %FALSE otherwise + * + * Since: 2.26 + */ +gboolean +g_application_get_action_enabled (GApplication *application, + const gchar *name) +{ + GApplicationAction *action; + + g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (!application->priv->is_remote, FALSE); + + action = g_hash_table_lookup (application->priv->actions, name); + g_return_val_if_fail (action != NULL, FALSE); + + return action->enabled; +} + +/** + * g_application_run: + * @application: a #GApplication + * + * Starts the application. + * + * The default implementation of this virtual function will simply run + * a main loop. + * + * It is an error to call this function if @application is a proxy for + * a remote application. + * + * Since: 2.26 + */ +void +g_application_run (GApplication *application) +{ + g_return_if_fail (G_IS_APPLICATION (application)); + g_return_if_fail (!application->priv->is_remote); + + G_APPLICATION_GET_CLASS (application)->run (application); +} + +/** + * g_application_quit: + * @application: a #GApplication + * @timestamp: Platform-specific event timestamp, may be 0 for default + * + * Request that the application quits. + * + * This function has different behavior depending on whether @application + * is acting as a proxy for another process. In the normal case where + * the current process is hosting the application, the default + * implementation will quit the main loop created by g_application_run(). + * + * If @application is a proxy, then the remote process will be asked + * to quit. + * + * Returns: %TRUE if the application accepted the request, %FALSE otherwise + * + * Since: 2.26 + */ +gboolean +g_application_quit (GApplication *application, + guint timestamp) +{ + gboolean retval = FALSE; + + g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); + + if (application->priv->is_remote) + { + _g_application_platform_remote_quit (application, timestamp); + retval = TRUE; + } + else + g_signal_emit (application, application_signals[QUIT], 0, timestamp, &retval); + + return retval; +} + +/** + * g_application_get_instance: + * + * In the normal case where there is exactly one #GApplication instance + * in this process, return that instance. If there are multiple, the + * first one created will be returned. Otherwise, return %NULL. + * + * Returns: (transfer none): The primary instance of #GApplication, + * or %NULL if none is set + * + * Since: 2.26 + */ +GApplication * +g_application_get_instance (void) +{ + return primary_application; +} + +/** + * g_application_get_id: + * + * Retrieves the platform-specific identifier for the #GApplication. + * + * Return value: The platform-specific identifier. The returned string + * is owned by the #GApplication instance and it should never be + * modified or freed + * + * Since: 2.26 + */ +G_CONST_RETURN char * +g_application_get_id (GApplication *application) +{ + g_return_val_if_fail (G_IS_APPLICATION (application), NULL); + + return application->priv->appid; +} + +/** + * g_application_is_remote: + * @application: a #GApplication + * + * Returns: %TRUE if this object represents a proxy for a remote application. + */ +gboolean +g_application_is_remote (GApplication *application) +{ + g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); + + return application->priv->is_remote; +} + +static void +g_application_init (GApplication *app) +{ + app->priv = G_TYPE_INSTANCE_GET_PRIVATE (app, + G_TYPE_APPLICATION, + GApplicationPrivate); + + app->priv->actions = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, + g_application_action_free); + app->priv->default_quit = TRUE; + app->priv->is_remote = TRUE; +} + +static void +g_application_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GApplication *app = G_APPLICATION (object); + + switch (prop_id) + { + case PROP_APPID: + g_value_set_string (value, g_application_get_id (app)); + break; + + case PROP_DEFAULT_QUIT: + g_value_set_boolean (value, app->priv->default_quit); + break; + + case PROP_IS_REMOTE: + g_value_set_boolean (value, g_application_is_remote (app)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_application_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GApplication *app = G_APPLICATION (object); + + switch (prop_id) + { + case PROP_APPID: + g_return_if_fail (_g_application_validate_id (g_value_get_string (value))); + app->priv->appid = g_value_dup_string (value); + break; + + case PROP_DEFAULT_QUIT: + app->priv->default_quit = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static GObject* +g_application_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GApplication *app; + GObject *object; + const char *appid = NULL; + 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); + } + + 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); + + if (primary_application == NULL) + primary_application = app; + g_hash_table_insert (instances_for_appid, g_strdup (appid), app); + + return object; +} + +static void +g_application_finalize (GObject *object) +{ + GApplication *app = G_APPLICATION (object); + + g_free (app->priv->appid); + if (app->priv->actions) + g_hash_table_unref (app->priv->actions); + if (app->priv->actions_changed_id) + g_source_remove (app->priv->actions_changed_id); + if (app->priv->mainloop) + g_main_loop_unref (app->priv->mainloop); + +#ifdef G_OS_UNIX + g_free (app->priv->dbus_path); + if (app->priv->session_bus) + g_object_unref (app->priv->session_bus); +#endif + + G_OBJECT_CLASS (g_application_parent_class)->finalize (object); +} + +static void +g_application_class_init (GApplicationClass *klass) +{ + GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GApplicationPrivate)); + + gobject_class->constructor = g_application_constructor; + gobject_class->set_property = g_application_set_property; + gobject_class->get_property = g_application_get_property; + + gobject_class->finalize = g_application_finalize; + + klass->run = g_application_default_run; + klass->quit = g_application_default_quit; + + application_signals[QUIT] = + g_signal_new (g_intern_static_string ("quit"), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GApplicationClass, quit), + g_signal_accumulator_true_handled, NULL, + _gio_marshal_BOOLEAN__UINT, + G_TYPE_BOOLEAN, 1, + G_TYPE_UINT); + + application_signals[ACTION] = + g_signal_new (g_intern_static_string ("action"), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED, + G_STRUCT_OFFSET (GApplicationClass, action), + NULL, NULL, + _gio_marshal_VOID__STRING_INT, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_INT); + + /** + * 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. Additional platform-dependent data is + * stored in @platform_data. + */ + + 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, prepare_activation), + NULL, NULL, + _gio_marshal_VOID__BOXED_BOXED, + G_TYPE_NONE, 2, + G_TYPE_VARIANT, + G_TYPE_VARIANT); + + /** + * GApplication:appid: + * + * The unique identifier for this application. See the documentation for + * #GApplication for more information about this property. + * + */ + g_object_class_install_property (gobject_class, + PROP_APPID, + g_param_spec_string ("appid", + P_("Application ID"), + P_("Identifier for this application"), + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * GApplication:default-quit: + * + * By default, if a different process is running this application, the + * process will be exited. Set this property to %FALSE to allow custom + * interaction with the remote process. + * + */ + g_object_class_install_property (gobject_class, + PROP_DEFAULT_QUIT, + g_param_spec_boolean ("default-quit", + P_("Default Quit"), + P_("Exit the process by default"), + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + + /** + * GApplication:is-remote: + * + * This property is %TRUE if this application instance represents a proxy + * to the instance of this application in another process. + * + */ + g_object_class_install_property (gobject_class, + PROP_IS_REMOTE, + g_param_spec_boolean ("is-remote", + P_("Is Remote"), + P_("Whether this application is a proxy for another process"), + TRUE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); +} + +#define __G_APPLICATION_C__ +#include "gioaliasdef.c" |