X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgapplication.c;h=fe941833e343f340f60bfedb4d40de68b44de4e5;hb=41c19c7df8f13101a40e7df115efbb8cd8de3f67;hp=6522aaa2dac31723c70cc70b217c68277bc777ad;hpb=b0e45c97992499929f1393743935438e07e88326;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gapplication.c b/gio/gapplication.c index 6522aaa..fe94183 100644 --- a/gio/gapplication.c +++ b/gio/gapplication.c @@ -27,9 +27,10 @@ #include "gapplicationcommandline.h" #include "gapplicationimpl.h" #include "gactiongroup.h" +#include "gmenumodel.h" +#include "gsettings.h" #include "gioenumtypes.h" -#include "gio-marshal.h" #include "gioenums.h" #include "gfile.h" @@ -38,7 +39,7 @@ #include /** - * SECTION: gapplication + * SECTION:gapplication * @title: GApplication * @short_description: Core application class * @@ -60,23 +61,99 @@ * Before using GApplication, you must choose an "application identifier". * The expected form of an application identifier is very close to that of * of a DBus bus name. - * Examples include: "com.example.MyApp" "org.example.internal-apps.Calculator" - * For convenience, the restrictions on application identifiers are reproduced - * here: - * - * Application identifiers must contain only the ASCII characters "[A-Z][a-z][0-9]_-" and must not begin with a digit. - * Application identifiers must contain at least one '.' (period) character (and thus at least two elements). - * Application identifiers must not begin with a '.' (period) character. - * Application identifiers must not contain consecutive '.' (period) characters. - * Application identifiers must not exceed 255 characters. - * + * Examples include: "com.example.MyApp", "org.example.internal-apps.Calculator". + * For details on valid application identifiers, see + * g_application_id_is_valid(). + * + * The application identifier is claimed by the application as a + * well-known bus name on the user's session bus. This means that the + * uniqueness of your application is scoped to the current session. It + * also means that your application may provide additional services + * (through registration of other object paths) at that bus name. + * + * The registration of these object paths should be done with the shared + * GDBus session bus. Note that due to the internal architecture of + * GDBus, method calls can be dispatched at any time (even if a main + * loop is not running). For this reason, you must ensure that any + * object paths that you wish to register are registered before + * #GApplication attempts to acquire the bus name of your application + * (which happens in g_application_register()). Unfortunately, this + * means that you cannot use g_application_get_is_remote() to decide if + * you want to register object paths. * * GApplication provides convenient life cycle management by maintaining * a use count for the primary application instance. * The use count can be changed using g_application_hold() and * g_application_release(). If it drops to zero, the application exits. * - * Opening files with a GApplicationFIXME: MISSING XINCLUDE CONTENT + * GApplication also implements the #GActionGroup interface and lets you + * easily export actions by adding them with g_application_set_action_group(). + * When invoking an action by calling g_action_group_activate_action() on + * the application, it is always invoked in the primary instance. The actions + * are also exported on the session bus, and GIO provides the #GDBusActionGroup + * wrapper to conveniently access them remotely. Additionally, + * g_application_set_menu() can be used to export representation data + * for the actions, in the form of a #GMenuModel. + * + * There is a number of different entry points into a #GApplication: + * + * via 'Activate' (i.e. just starting the application) + * via 'Open' (i.e. opening some files) + * by handling a command-line + * via activating an action + * + * The #GApplication::startup signal lets you handle the application + * initialization for all of these in a single place. + * + * Regardless of which of these entry points is used to start the application, + * GApplication passes some platform + * data from the launching instance to the primary instance, + * in the form of a #GVariant dictionary mapping strings to variants. + * To use platform data, override the @before_emit or @after_emit virtual + * functions in your #GApplication subclass. When dealing with + * #GApplicationCommandline objects, the platform data is directly + * available via g_application_command_line_get_cwd(), + * g_application_command_line_get_environ() and + * g_application_command_line_get_platform_data(). + * + * As the name indicates, the platform data may vary depending on the + * operating system, but it always includes the current directory (key + * "cwd"), and optionally the environment (ie the set of environment + * variables and their values) of the calling process (key "environ"). + * The environment is only added to the platform data if the + * #G_APPLICATION_SEND_ENVIONMENT flag is set. GApplication subclasses + * can add their own platform data by overriding the @add_platform_data + * virtual function. For instance, #GtkApplication adds startup notification + * data in this way. + * + * To parse commandline arguments you may handle the + * #GApplication::command-line signal or override the local_command_line() + * vfunc, to parse them in either the primary instance or the local instance, + * respectively. + * + * Opening files with a GApplication + * + * + * FIXME: MISSING XINCLUDE CONTENT + * + * + * + * + * A GApplication with actions + * + * + * FIXME: MISSING XINCLUDE CONTENT + * + * + * + * + * A GApplication with menus + * + * + * FIXME: MISSING XINCLUDE CONTENT + * + * + * */ struct _GApplicationPrivate @@ -85,7 +162,7 @@ struct _GApplicationPrivate gchar *id; GActionGroup *actions; - GMainLoop *mainloop; + GMenuModel *menu; guint inactivity_timeout_id; guint inactivity_timeout; @@ -93,7 +170,10 @@ struct _GApplicationPrivate guint is_registered : 1; guint is_remote : 1; + guint did_startup : 1; + guint did_shutdown : 1; + GActionGroup *remote_actions; GApplicationImpl *impl; }; @@ -105,12 +185,14 @@ enum PROP_IS_REGISTERED, PROP_IS_REMOTE, PROP_INACTIVITY_TIMEOUT, - PROP_ACTION_GROUP + PROP_ACTION_GROUP, + PROP_MENU }; enum { SIGNAL_STARTUP, + SIGNAL_SHUTDOWN, SIGNAL_ACTIVATE, SIGNAL_OPEN, SIGNAL_ACTION, @@ -141,6 +223,13 @@ g_application_real_after_emit (GApplication *application, static void g_application_real_startup (GApplication *application) { + application->priv->did_startup = TRUE; +} + +static void +g_application_real_shutdown (GApplication *application) +{ + application->priv->did_shutdown = TRUE; } static void @@ -148,7 +237,8 @@ g_application_real_activate (GApplication *application) { if (!g_signal_has_handler_pending (application, g_application_signals[SIGNAL_ACTIVATE], - 0, TRUE)) + 0, TRUE) && + G_APPLICATION_GET_CLASS (application)->activate == g_application_real_activate) { static gboolean warned; @@ -170,7 +260,8 @@ g_application_real_open (GApplication *application, { if (!g_signal_has_handler_pending (application, g_application_signals[SIGNAL_OPEN], - 0, TRUE)) + 0, TRUE) && + G_APPLICATION_GET_CLASS (application)->open == g_application_real_open) { static gboolean warned; @@ -188,18 +279,24 @@ static int g_application_real_command_line (GApplication *application, GApplicationCommandLine *cmdline) { - static gboolean warned; + if (!g_signal_has_handler_pending (application, + g_application_signals[SIGNAL_COMMAND_LINE], + 0, TRUE) && + G_APPLICATION_GET_CLASS (application)->command_line == g_application_real_command_line) + { + static gboolean warned; - if (warned) - return 1; + if (warned) + return 1; - g_warning ("Your application claims to support custom command line " - "handling but does not implement g_application_command_line() " - "and has no handlers connected to the 'command-line' signal."); + g_warning ("Your application claims to support custom command line " + "handling but does not implement g_application_command_line() " + "and has no handlers connected to the 'command-line' signal."); - warned = TRUE; + warned = TRUE; + } - return 1; + return 1; } static gboolean @@ -227,7 +324,7 @@ g_application_real_local_command_line (GApplication *application, if (application->priv->flags & G_APPLICATION_IS_SERVICE) { - if (n_args > 1) + if ((*exit_status = n_args > 1)) { g_printerr ("GApplication service mode takes no arguments.\n"); application->priv->flags &= ~G_APPLICATION_IS_SERVICE; @@ -281,22 +378,6 @@ g_application_real_add_platform_data (GApplication *application, { } -static void -g_application_real_quit_mainloop (GApplication *application) -{ - if (application->priv->mainloop != NULL) - g_main_loop_quit (application->priv->mainloop); -} - -static void -g_application_real_run_mainloop (GApplication *application) -{ - if (application->priv->mainloop == NULL) - application->priv->mainloop = g_main_loop_new (NULL, FALSE); - - g_main_loop_run (application->priv->mainloop); -} - /* GObject implementation stuff {{{1 */ static void g_application_set_property (GObject *object, @@ -327,6 +408,11 @@ g_application_set_property (GObject *object, g_value_get_object (value)); break; + case PROP_MENU: + g_application_set_menu (application, + g_value_get_object (value)); + break; + default: g_assert_not_reached (); } @@ -335,11 +421,11 @@ g_application_set_property (GObject *object, /** * g_application_set_action_group: * @application: a #GApplication - * @action_group: a #GActionGroup, or %NULL + * @action_group: (allow-none): a #GActionGroup, or %NULL * * Sets or unsets the group of actions associated with the application. * - * These actions are the actions that can be remotely invoked. + * These actions can be invoked remotely. * * It is an error to call this function after the application has been * registered. @@ -351,7 +437,7 @@ g_application_set_action_group (GApplication *application, GActionGroup *action_group) { g_return_if_fail (G_IS_APPLICATION (application)); - g_return_if_fail (application->priv->is_registered); + g_return_if_fail (!application->priv->is_registered); if (application->priv->actions != NULL) g_object_unref (application->priv->actions); @@ -362,6 +448,54 @@ g_application_set_action_group (GApplication *application, g_object_ref (application->priv->actions); } +/** + * g_application_set_menu: + * @application: a #GApplication + * @menu: (allow-none): a #GMenuModel, or %NULL + * + * Sets or unsets the menu associated with the application. The menu + * provides representation data for the exported actions of @application. + * + * It is an error to call this function after the application has been + * registered. + * + * Since: 2.32 + */ +void +g_application_set_menu (GApplication *application, + GMenuModel *menu) +{ + g_return_if_fail (G_IS_APPLICATION (application)); + g_return_if_fail (!application->priv->is_registered); + + if (application->priv->menu != NULL) + g_object_unref (application->priv->menu); + + application->priv->menu = menu; + + if (application->priv->menu != NULL) + g_object_ref (application->priv->menu); +} + +/** + * g_application_get_menu: + * @application: a #GApplication + * + * Returns the menu model that has been set + * with g_application_set_menu(). + * + * Returns: the #GMenuModel associated with @application + * + * Since: 2.32 + */ +GMenuModel * +g_application_get_menu (GApplication *application) +{ + g_return_val_if_fail (G_IS_APPLICATION (application), NULL); + + return application->priv->menu; +} + static void g_application_get_property (GObject *object, guint prop_id, @@ -408,6 +542,9 @@ g_application_constructed (GObject *object) GApplication *application = G_APPLICATION (object); g_assert (application->priv->id != NULL); + + if (g_application_get_default () == NULL) + g_application_set_default (application); } static void @@ -419,8 +556,8 @@ g_application_finalize (GObject *object) g_application_impl_destroy (application->priv->impl); g_free (application->priv->id); - if (application->priv->mainloop) - g_main_loop_unref (application->priv->mainloop); + if (g_application_get_default () == application) + g_application_set_default (NULL); G_OBJECT_CLASS (g_application_parent_class) ->finalize (object); @@ -447,13 +584,12 @@ g_application_class_init (GApplicationClass *class) class->before_emit = g_application_real_before_emit; class->after_emit = g_application_real_after_emit; class->startup = g_application_real_startup; + class->shutdown = g_application_real_shutdown; class->activate = g_application_real_activate; class->open = g_application_real_open; class->command_line = g_application_real_command_line; class->local_command_line = g_application_real_local_command_line; class->add_platform_data = g_application_real_add_platform_data; - class->quit_mainloop = g_application_real_quit_mainloop; - class->run_mainloop = g_application_real_run_mainloop; g_object_class_install_property (object_class, PROP_APPLICATION_ID, g_param_spec_string ("application-id", @@ -482,16 +618,24 @@ g_application_class_init (GApplicationClass *class) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_INACTIVITY_TIMEOUT, - g_param_spec_boolean ("inactivity-timeout", - P_("Inactivity timeout"), - P_("Iime (ms) to stay alive after becoming idle"), - FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_uint ("inactivity-timeout", + P_("Inactivity timeout"), + P_("Time (ms) to stay alive after becoming idle"), + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_ACTION_GROUP, g_param_spec_object ("action-group", P_("Action group"), P_("The group of actions that the application exports"), - G_TYPE_ACTION_GROUP, + G_TYPE_ACTION_GROUP, + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_MENU, + g_param_spec_object ("menu", + P_("Menu model"), + P_("The menu that the application exports"), + G_TYPE_MENU_MODEL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); /** @@ -499,7 +643,7 @@ g_application_class_init (GApplicationClass *class) * @application: the application * * The ::startup signal is emitted on the primary instance immediately - * after registration. See g_activation_register(). + * after registration. See g_application_register(). */ g_application_signals[SIGNAL_STARTUP] = g_signal_new ("startup", G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, @@ -507,6 +651,18 @@ g_application_class_init (GApplicationClass *class) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** + * GApplication::shutdown: + * @application: the application + * + * The ::shutdown signal is emitted only on the registered primary instance + * immediately after the main loop terminates. + */ + g_application_signals[SIGNAL_SHUTDOWN] = + g_signal_new ("shutdown", G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GApplicationClass, shutdown), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /** * GApplication::activate: * @application: the application * @@ -522,7 +678,7 @@ g_application_class_init (GApplicationClass *class) /** * GApplication::open: * @application: the application - * @files: an array of #GFile objects + * @files: (array length=n_files) (element-type GFile): an array of #GFiles * @n_files: the length of @files * @hint: a hint provided by the calling instance * @@ -532,7 +688,7 @@ g_application_class_init (GApplicationClass *class) g_application_signals[SIGNAL_OPEN] = g_signal_new ("open", G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GApplicationClass, open), - NULL, NULL, _gio_marshal_VOID__POINTER_INT_STRING, + NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_STRING); /** @@ -542,14 +698,17 @@ g_application_class_init (GApplicationClass *class) * passed commandline * * The ::command-line signal is emitted on the primary instance when - * a commandline is not handled locally. See g_application_run() for - * more information. + * a commandline is not handled locally. See g_application_run() and + * the #GApplicationCommandline documentation for more information. + * + * Returns: An integer that is set as the exit status for the calling + * process. See g_application_command_line_set_exit_status(). */ g_application_signals[SIGNAL_COMMAND_LINE] = g_signal_new ("command-line", G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GApplicationClass, command_line), g_signal_accumulator_first_wins, NULL, - _gio_marshal_INT__OBJECT, + NULL, G_TYPE_INT, 1, G_TYPE_APPLICATION_COMMAND_LINE); g_type_class_add_private (class, sizeof (GApplicationPrivate)); @@ -570,6 +729,18 @@ get_platform_data (GApplication *application) g_free (cwd); } + if (application->priv->flags & G_APPLICATION_SEND_ENVIRONMENT) + { + GVariant *array; + gchar **envp; + + envp = g_get_environ (); + array = g_variant_new_bytestring_array ((const gchar **) envp, -1); + g_strfreev (envp); + + g_variant_builder_add (builder, "{sv}", "environ", array); + } + G_APPLICATION_GET_CLASS (application)-> add_platform_data (application, builder); @@ -584,52 +755,81 @@ get_platform_data (GApplication *application) /** * g_application_id_is_valid: * @application_id: a potential application identifier - * @returns: %TRUE if @application_id is valid * - * Checks if @application_id is a valid application ID. A valid ID is - * required for calls to g_application_new() and + * Checks if @application_id is a valid application identifier. + * + * A valid ID is required for calls to g_application_new() and * g_application_set_application_id(). + * + * For convenience, the restrictions on application identifiers are + * reproduced here: + * + * Application identifiers must contain only the ASCII characters "[A-Z][a-z][0-9]_-." and must not begin with a digit. + * Application identifiers must contain at least one '.' (period) character (and thus at least three elements). + * Application identifiers must not begin or end with a '.' (period) character. + * Application identifiers must not contain consecutive '.' (period) characters. + * Application identifiers must not exceed 255 characters. + * + * + * Returns: %TRUE if @application_id is valid **/ gboolean g_application_id_is_valid (const gchar *application_id) { + gsize len; gboolean allow_dot; + gboolean has_dot; + + len = strlen (application_id); + + if (len > 255) + return FALSE; - if (strlen (application_id) > 255) + if (!g_ascii_isalpha (application_id[0])) return FALSE; - if (!g_ascii_isalpha (*application_id)) + if (application_id[len-1] == '.') return FALSE; application_id++; - allow_dot = FALSE; + allow_dot = TRUE; + has_dot = FALSE; for (; *application_id; application_id++) { if (g_ascii_isalnum (*application_id) || (*application_id == '-') || (*application_id == '_')) - allow_dot = TRUE; + { + allow_dot = TRUE; + } else if (allow_dot && *application_id == '.') - allow_dot = FALSE; + { + has_dot = TRUE; + allow_dot = FALSE; + } else return FALSE; } + if (!has_dot) + return FALSE; + return TRUE; } - + /* Public Constructor {{{1 */ /** * g_application_new: * @application_id: the application id * @flags: the application flags - * @returns: a new #GApplication instance * * Creates a new #GApplication instance. * * This function calls g_type_init() for you. * * The application id must be valid. See g_application_id_is_valid(). + * + * Returns: a new #GApplication instance **/ GApplication * g_application_new (const gchar *application_id, @@ -649,10 +849,11 @@ g_application_new (const gchar *application_id, /** * g_application_get_application_id: * @application: a #GApplication - * @returns: the identifier for @application, owned by @application * * Gets the unique identifier for @application. * + * Returns: the identifier for @application, owned by @application + * * Since: 2.28 **/ const gchar * @@ -698,12 +899,13 @@ g_application_set_application_id (GApplication *application, /** * g_application_get_flags: * @application: a #GApplication - * @returns: the flags for @application * * Gets the flags for @application. * * See #GApplicationFlags. * + * Returns: the flags for @application + * * Since: 2.28 **/ GApplicationFlags @@ -779,8 +981,6 @@ g_application_get_inactivity_timeout (GApplication *application) * used for next time g_application_release() drops the use count to * zero. Any timeouts currently in progress are not impacted. * - * Returns: the timeout, in milliseconds - * * Since: 2.28 **/ void @@ -800,13 +1000,14 @@ g_application_set_inactivity_timeout (GApplication *application, /** * g_application_get_is_registered: * @application: a #GApplication - * @returns: %TRUE if @application is registered * * Checks if @application is registered. * * An application is registered if g_application_register() has been * successfully called. * + * Returns: %TRUE if @application is registered + * * Since: 2.28 **/ gboolean @@ -820,7 +1021,6 @@ g_application_get_is_registered (GApplication *application) /** * g_application_get_is_remote: * @application: a #GApplication - * @returns: %TRUE if @application is remote * * Checks if @application is remote. * @@ -829,10 +1029,12 @@ g_application_get_is_registered (GApplication *application) * perform actions on @application will result in the actions being * performed by the primary instance. * - * The value of this property can not be accessed before + * The value of this property cannot be accessed before * g_application_register() has been called. See * g_application_get_is_registered(). * + * Returns: %TRUE if @application is remote + * * Since: 2.28 **/ gboolean @@ -850,18 +1052,24 @@ g_application_get_is_remote (GApplication *application) * @application: a #GApplication * @cancellable: a #GCancellable, or %NULL * @error: a pointer to a NULL #GError, or %NULL - * @returns: %TRUE if registration succeeded * * Attempts registration of the application. * * This is the point at which the application discovers if it is the * primary instance or merely acting as a remote for an already-existing - * primary instance. + * primary instance. This is implemented by attempting to acquire the + * application identifier as a unique bus name on the session bus using + * GDBus. + * + * Due to the internal architecture of GDBus, method calls can be + * dispatched at any time (even if a main loop is not running). For + * this reason, you must ensure that any object paths that you wish to + * register are registered before calling this function. * * If the application has already been registered then %TRUE is * returned with no work performed. * - * The startup() virtual function is invoked if registration succeeds + * The #GApplication::startup signal is emitted if registration succeeds * and @application is the primary instance. * * In the event of an error (such as @cancellable being cancelled, or a @@ -872,6 +1080,8 @@ g_application_get_is_remote (GApplication *application) * instance is or is not the primary instance of the application. See * g_application_get_is_remote() for that. * + * Returns: %TRUE if registration succeeded + * * Since: 2.28 **/ gboolean @@ -883,29 +1093,32 @@ g_application_register (GApplication *application, if (!application->priv->is_registered) { - gboolean is_remote; - gboolean try; - - /* don't try to be the primary instance if - * G_APPLICATION_IS_LAUNCHER was specified. - */ - try = !(application->priv->flags & G_APPLICATION_IS_LAUNCHER); - - application->priv->impl = - g_application_impl_register (application, application->priv->id, - application->priv->flags, - &is_remote, cancellable, error); - - if (application->priv->impl == NULL) - return FALSE; + if (~application->priv->flags & G_APPLICATION_NON_UNIQUE) + { + application->priv->impl = + g_application_impl_register (application, application->priv->id, + application->priv->flags, + &application->priv->remote_actions, + cancellable, error); + + if (application->priv->impl == NULL) + return FALSE; + } - application->priv->is_remote = is_remote; + application->priv->is_remote = application->priv->remote_actions != NULL; application->priv->is_registered = TRUE; g_object_notify (G_OBJECT (application), "is-registered"); - if (!is_remote) - g_signal_emit (application, g_application_signals[SIGNAL_STARTUP], 0); + if (!application->priv->is_remote) + { + g_signal_emit (application, g_application_signals[SIGNAL_STARTUP], 0); + + if (!application->priv->did_startup) + g_critical ("GApplication subclass '%s' failed to chain up on" + " ::startup (from start of override function)", + G_OBJECT_TYPE_NAME (application)); + } } return TRUE; @@ -919,7 +1132,7 @@ g_application_register (GApplication *application, * Increases the use count of @application. * * Use this function to indicate that the application has a reason to - * continue to run. For example, g_application_hold() is called by GTK+ + * continue to run. For example, g_application_hold() is called by GTK+ * when a toplevel window is on the screen. * * To cancel the hold, call g_application_release(). @@ -941,8 +1154,7 @@ inactivity_timeout_expired (gpointer data) { GApplication *application = G_APPLICATION (data); - G_APPLICATION_GET_CLASS (application) - ->quit_mainloop (application); + application->priv->inactivity_timeout_id = 0; return FALSE; } @@ -964,17 +1176,9 @@ g_application_release (GApplication *application) { application->priv->use_count--; - if (application->priv->use_count == 0) - { - if (application->priv->inactivity_timeout) - application->priv->inactivity_timeout_id = - g_timeout_add (application->priv->inactivity_timeout, - inactivity_timeout_expired, application); - - else - G_APPLICATION_GET_CLASS (application) - ->quit_mainloop (application); - } + if (application->priv->use_count == 0 && application->priv->inactivity_timeout) + application->priv->inactivity_timeout_id = g_timeout_add (application->priv->inactivity_timeout, + inactivity_timeout_expired, application); } /* Activate, Open {{{1 */ @@ -984,8 +1188,8 @@ g_application_release (GApplication *application) * * Activates the application. * - * In essence, this results in the activate() virtual function being - * invoked in the primary instance. + * In essence, this results in the #GApplication::activate() signal being + * emitted in the primary instance. * * The application must be registered before calling this function. * @@ -1008,26 +1212,24 @@ g_application_activate (GApplication *application) /** * g_application_open: * @application: a #GApplication - * @files: an array of #GFiles to open + * @files: (array length=n_files): an array of #GFiles to open * @n_files: the length of the @files array * @hint: a hint (or ""), but never %NULL * * Opens the given files. * - * In essence, this results in the open() virtual function being invoked + * In essence, this results in the #GApplication::open signal being emitted * in the primary instance. * * @n_files must be greater than zero. * - * @hint is simply passed through to the open() virtual function. It is + * @hint is simply passed through to the ::open signal. It is * intended to be used by applications that have multiple modes for * opening files (eg: "view" vs "edit", etc). Unless you have a need * for this functionality, you should use "". * - * The application must be registered before calling this function and - * it must have the %G_APPLICATION_HANDLES_OPEN flag set. The open() - * virtual function should also be implemented in order for anything - * meaningful to happen. + * The application must be registered before calling this function + * and it must have the %G_APPLICATION_HANDLES_OPEN flag set. * * Since: 2.28 **/ @@ -1056,20 +1258,39 @@ g_application_open (GApplication *application, /** * g_application_run: * @application: a #GApplication - * @argc: the argc from main() - * @argv: the argv from main() - * @returns: the exit status + * @argc: the argc from main() (or 0 if @argv is %NULL) + * @argv: (array length=argc) (allow-none): the argv from main(), or %NULL * * Runs the application. * * This function is intended to be run from main() and its return value - * is intended to be returned by main(). - * - * First, the local_command_line() virtual function is invoked. This - * function always runs on the local instance. If that function returns - * %FALSE then the application is registered and the #GApplication::command-line - * signal is emitted in the primary instance (which may or may not be - * this instance). + * is intended to be returned by main(). Although you are expected to pass + * the @argc, @argv parameters from main() to this function, it is possible + * to pass %NULL if @argv is not available or commandline handling is not + * required. + * + * First, the local_command_line() virtual function is invoked. + * This function always runs on the local instance. It gets passed a pointer + * to a %NULL-terminated copy of @argv and is expected to remove the arguments + * that it handled (shifting up remaining arguments). See + * for an example of + * parsing @argv manually. Alternatively, you may use the #GOptionContext API, + * after setting argc = g_strv_length (argv);. + * + * The last argument to local_command_line() is a pointer to the @status + * variable which can used to set the exit status that is returned from + * g_application_run(). + * + * If local_command_line() returns %TRUE, the command line is expected + * to be completely handled, including possibly registering as the primary + * instance, calling g_application_activate() or g_application_open(), etc. + * + * If local_command_line() returns %FALSE then the application is registered + * and the #GApplication::command-line signal is emitted in the primary + * instance (which may or may not be this instance). The signal handler + * gets passed a #GApplicationCommandline object that (among other things) + * contains the remaining commandline arguments that have not been handled + * by local_command_line(). * * If the application has the %G_APPLICATION_HANDLES_COMMAND_LINE * flag set then the default implementation of local_command_line() @@ -1085,20 +1306,30 @@ g_application_open (GApplication *application, * given and the %G_APPLICATION_HANDLES_OPEN flag is set then they * are assumed to be filenames and g_application_open() is called. * + * If you need to handle commandline arguments that are not filenames, + * and you don't mind commandline handling to happen in the primary + * instance, you should set %G_APPLICATION_HANDLED_COMMAND_LINE and + * process the commandline arguments in your #GApplication::command-line + * signal handler, either manually or using the #GOptionContext API. + * * If you are interested in doing more complicated local handling of the * commandline then you should implement your own #GApplication subclass - * and override local_command_line(). See + * and override local_command_line(). In this case, you most likely want + * to return %TRUE from your local_command_line() implementation to + * suppress the default handling. See * for an example. * * If, after the above is done, the use count of the application is zero * then the exit status is returned immediately. If the use count is - * non-zero then the mainloop is run until the use count falls to zero, - * at which point 0 is returned. + * non-zero then the default main context is iterated until the use count + * falls to zero, at which point 0 is returned. * * If the %G_APPLICATION_IS_SERVICE flag is set, then the exiting at * use count of zero is delayed for a while (ie: the instance stays * around to provide its service to others). * + * Returns: the exit status + * * Since: 2.28 **/ int @@ -1165,6 +1396,7 @@ g_application_run (GApplication *application, g_strfreev (arguments); if (application->priv->flags & G_APPLICATION_IS_SERVICE && + application->priv->is_registered && !application->priv->use_count && !application->priv->inactivity_timeout_id) { @@ -1172,30 +1404,28 @@ g_application_run (GApplication *application, g_timeout_add (10000, inactivity_timeout_expired, application); } - if (application->priv->use_count || - application->priv->inactivity_timeout_id) + while (application->priv->use_count || application->priv->inactivity_timeout_id) { - G_APPLICATION_GET_CLASS (application) - ->run_mainloop (application); + g_main_context_iteration (NULL, TRUE); status = 0; } - if (application->priv->impl) - g_application_impl_flush (application->priv->impl); + if (!application->priv->is_remote) + { + g_signal_emit (application, g_application_signals[SIGNAL_SHUTDOWN], 0); - return status; -} + if (!application->priv->did_shutdown) + g_critical ("GApplication subclass '%s' failed to chain up on" + " ::shutdown (from end of override function)", + G_OBJECT_TYPE_NAME (application)); + } -static gboolean -g_application_has_action (GActionGroup *action_group, - const gchar *action_name) -{ - GApplication *application = G_APPLICATION (action_group); + if (application->priv->impl) + g_application_impl_flush (application->priv->impl); - g_return_val_if_fail (application->priv->is_registered, FALSE); + g_settings_sync (); - return application->priv->actions && - g_action_group_has_action (application->priv->actions, action_name); + return status; } static gchar ** @@ -1205,7 +1435,10 @@ g_application_list_actions (GActionGroup *action_group) g_return_val_if_fail (application->priv->is_registered, NULL); - if (application->priv->actions != NULL) + if (application->priv->remote_actions != NULL) + return g_action_group_list_actions (application->priv->remote_actions); + + else if (application->priv->actions != NULL) return g_action_group_list_actions (application->priv->actions); else @@ -1214,68 +1447,37 @@ g_application_list_actions (GActionGroup *action_group) } static gboolean -g_application_get_action_enabled (GActionGroup *action_group, - const gchar *action_name) +g_application_query_action (GActionGroup *group, + const gchar *action_name, + gboolean *enabled, + const GVariantType **parameter_type, + const GVariantType **state_type, + GVariant **state_hint, + GVariant **state) { - GApplication *application = G_APPLICATION (action_group); + GApplication *application = G_APPLICATION (group); - g_return_val_if_fail (application->priv->actions != NULL, FALSE); g_return_val_if_fail (application->priv->is_registered, FALSE); - return g_action_group_get_action_enabled (application->priv->actions, - action_name); -} - -static const GVariantType * -g_application_get_action_parameter_type (GActionGroup *action_group, - const gchar *action_name) -{ - GApplication *application = G_APPLICATION (action_group); + if (application->priv->remote_actions != NULL) + return g_action_group_query_action (application->priv->remote_actions, + action_name, + enabled, + parameter_type, + state_type, + state_hint, + state); - g_return_val_if_fail (application->priv->actions != NULL, NULL); - g_return_val_if_fail (application->priv->is_registered, NULL); - - return g_action_group_get_action_parameter_type (application->priv->actions, - action_name); -} - -static const GVariantType * -g_application_get_action_state_type (GActionGroup *action_group, - const gchar *action_name) -{ - GApplication *application = G_APPLICATION (action_group); - - g_return_val_if_fail (application->priv->actions != NULL, NULL); - g_return_val_if_fail (application->priv->is_registered, NULL); - - return g_action_group_get_action_state_type (application->priv->actions, - action_name); -} - -static GVariant * -g_application_get_action_state_hint (GActionGroup *action_group, - const gchar *action_name) -{ - GApplication *application = G_APPLICATION (action_group); - - g_return_val_if_fail (application->priv->actions != NULL, NULL); - g_return_val_if_fail (application->priv->is_registered, NULL); - - return g_action_group_get_action_state_hint (application->priv->actions, - action_name); -} - -static GVariant * -g_application_get_action_state (GActionGroup *action_group, - const gchar *action_name) -{ - GApplication *application = G_APPLICATION (action_group); - - g_return_val_if_fail (application->priv->actions != NULL, NULL); - g_return_val_if_fail (application->priv->is_registered, NULL); + if (application->priv->actions != NULL) + return g_action_group_query_action (application->priv->actions, + action_name, + enabled, + parameter_type, + state_type, + state_hint, + state); - return g_action_group_get_action_state (application->priv->actions, - action_name); + return FALSE; } static void @@ -1285,11 +1487,16 @@ g_application_change_action_state (GActionGroup *action_group, { GApplication *application = G_APPLICATION (action_group); - g_return_if_fail (application->priv->actions != NULL); + g_return_if_fail (application->priv->is_remote || + application->priv->actions != NULL); g_return_if_fail (application->priv->is_registered); - g_action_group_change_action_state (application->priv->actions, - action_name, value); + if (application->priv->remote_actions) + return g_action_group_change_action_state (application->priv->remote_actions, action_name, value); + + else + g_action_group_change_action_state (application->priv->actions, + action_name, value); } static void @@ -1299,27 +1506,69 @@ g_application_activate_action (GActionGroup *action_group, { GApplication *application = G_APPLICATION (action_group); - g_return_if_fail (application->priv->actions != NULL); + g_return_if_fail (application->priv->is_remote || + application->priv->actions != NULL); g_return_if_fail (application->priv->is_registered); - g_action_group_activate_action (application->priv->actions, - action_name, parameter); + if (application->priv->remote_actions) + return g_action_group_change_action_state (application->priv->remote_actions, action_name, parameter); + + else + g_action_group_activate_action (application->priv->actions, + action_name, parameter); } static void g_application_action_group_iface_init (GActionGroupInterface *iface) { - iface->has_action = g_application_has_action; iface->list_actions = g_application_list_actions; - - iface->get_action_enabled = g_application_get_action_enabled; - iface->get_action_parameter_type = g_application_get_action_parameter_type; - iface->get_action_state_type = g_application_get_action_state_type; - iface->get_action_state_hint = g_application_get_action_state_hint; - iface->get_action_state = g_application_get_action_state; + iface->query_action = g_application_query_action; iface->change_action_state = g_application_change_action_state; iface->activate_action = g_application_activate_action; } +/* Default Application {{{1 */ + +static GApplication *default_app; + +/** + * g_application_get_default: + * @returns: (transfer none): the default application for this process, or %NULL + * + * Returns the default #GApplication instance for this process. + * + * Normally there is only one #GApplication per process and it becomes + * the default when it is created. You can exercise more control over + * this by using g_application_set_default(). + * + * If there is no default application then %NULL is returned. + * + * Since: 2.32 + **/ +GApplication * +g_application_get_default (void) +{ + return default_app; +} + +/** + * g_application_set_default: + * @application: the application to set as default, or %NULL + * + * Sets or unsets the default application for the process, as returned + * by g_application_get_default(). + * + * This function does not take its own reference on @application. If + * @application is destroyed then the default application will revert + * back to %NULL. + * + * Since: 2.32 + **/ +void +g_application_set_default (GApplication *application) +{ + default_app = application; +} + /* Epilogue {{{1 */ /* vim:set foldmethod=marker: */