X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgapplication.c;h=fe941833e343f340f60bfedb4d40de68b44de4e5;hb=41c19c7df8f13101a40e7df115efbb8cd8de3f67;hp=4ca811c3968cac0313528546982c71f19888b29a;hpb=cb647730029d5da388637e2a532f7f54a0d86f47;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gapplication.c b/gio/gapplication.c index 4ca811c..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 * @@ -64,11 +65,72 @@ * 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. * + * 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 * * @@ -76,6 +138,22 @@ * * * + * + * A GApplication with actions + * + * + * FIXME: MISSING XINCLUDE CONTENT + * + * + * + * + * A GApplication with menus + * + * + * FIXME: MISSING XINCLUDE CONTENT + * + * + * */ struct _GApplicationPrivate @@ -84,7 +162,7 @@ struct _GApplicationPrivate gchar *id; GActionGroup *actions; - GMainLoop *mainloop; + GMenuModel *menu; guint inactivity_timeout_id; guint inactivity_timeout; @@ -92,8 +170,10 @@ struct _GApplicationPrivate guint is_registered : 1; guint is_remote : 1; + guint did_startup : 1; + guint did_shutdown : 1; - GHashTable *remote_actions; /* string -> RemoteActionInfo */ + 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 @@ -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. @@ -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", @@ -484,7 +620,7 @@ g_application_class_init (GApplicationClass *class) g_object_class_install_property (object_class, PROP_INACTIVITY_TIMEOUT, g_param_spec_uint ("inactivity-timeout", P_("Inactivity timeout"), - P_("Iime (ms) to stay alive after becoming idle"), + P_("Time (ms) to stay alive after becoming idle"), 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -492,7 +628,14 @@ g_application_class_init (GApplicationClass *class) 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)); /** @@ -500,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, @@ -508,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 * @@ -523,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 * @@ -533,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); /** @@ -543,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)); @@ -575,7 +733,7 @@ get_platform_data (GApplication *application) { GVariant *array; gchar **envp; - + envp = g_get_environ (); array = g_variant_new_bytestring_array ((const gchar **) envp, -1); g_strfreev (envp); @@ -597,7 +755,6 @@ 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 identifier. * @@ -607,53 +764,72 @@ get_platform_data (GApplication *application) * 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 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, @@ -673,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 * @@ -722,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 @@ -803,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 @@ -824,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 @@ -844,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. * @@ -853,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 @@ -874,13 +1052,19 @@ 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. @@ -896,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 @@ -907,14 +1093,17 @@ g_application_register (GApplication *application, if (!application->priv->is_registered) { - 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; + 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 = application->priv->remote_actions != NULL; application->priv->is_registered = TRUE; @@ -922,7 +1111,14 @@ g_application_register (GApplication *application, g_object_notify (G_OBJECT (application), "is-registered"); if (!application->priv->is_remote) - g_signal_emit (application, g_application_signals[SIGNAL_STARTUP], 0); + { + 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; @@ -936,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(). @@ -958,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; } @@ -981,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 */ @@ -1025,7 +1212,7 @@ 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 * @@ -1071,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() @@ -1100,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 @@ -1188,34 +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); - - return status; -} + if (!application->priv->is_remote) + { + g_signal_emit (application, g_application_signals[SIGNAL_SHUTDOWN], 0); -static gboolean -g_application_has_action (GActionGroup *action_group, - const gchar *action_name) -{ - GApplication *application = G_APPLICATION (action_group); + 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)); + } - g_return_val_if_fail (application->priv->is_registered, FALSE); + if (application->priv->impl) + g_application_impl_flush (application->priv->impl); - if (application->priv->remote_actions != NULL) - return g_hash_table_lookup (application->priv->remote_actions, - action_name) != NULL; + g_settings_sync (); - return application->priv->actions && - g_action_group_has_action (application->priv->actions, action_name); + return status; } static gchar ** @@ -1226,23 +1436,7 @@ g_application_list_actions (GActionGroup *action_group) g_return_val_if_fail (application->priv->is_registered, NULL); if (application->priv->remote_actions != NULL) - { - GHashTableIter iter; - gint n, i = 0; - gchar **keys; - gpointer key; - - n = g_hash_table_size (application->priv->remote_actions); - keys = g_new (gchar *, n + 1); - - g_hash_table_iter_init (&iter, application->priv->remote_actions); - while (g_hash_table_iter_next (&iter, &key, NULL)) - keys[i++] = g_strdup (key); - g_assert_cmpint (i, ==, n); - keys[n] = NULL; - - return keys; - } + 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); @@ -1253,104 +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); - if (application->priv->remote_actions) - { - RemoteActionInfo *info; - - info = g_hash_table_lookup (application->priv->remote_actions, - action_name); - - return info && info->enabled; - } - - 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); - - g_return_val_if_fail (application->priv->actions != NULL, NULL); - g_return_val_if_fail (application->priv->is_registered, NULL); - - if (application->priv->remote_actions) - { - RemoteActionInfo *info; - - info = g_hash_table_lookup (application->priv->remote_actions, - action_name); - - if (info) - return info->parameter_type; - else - return 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); - - if (application->priv->remote_actions) - { - RemoteActionInfo *info; - - info = g_hash_table_lookup (application->priv->remote_actions, - action_name); - - if (info && info->state) - return g_variant_get_type (info->state); - else - return NULL; - } - - return g_action_group_get_action_state_type (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->remote_actions) - { - RemoteActionInfo *info; - - info = g_hash_table_lookup (application->priv->remote_actions, - action_name); + 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); - if (info && info->state) - return g_variant_ref (info->state); - else - return 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 @@ -1360,12 +1487,12 @@ g_application_change_action_state (GActionGroup *action_group, { GApplication *application = G_APPLICATION (action_group); + g_return_if_fail (application->priv->is_remote || + application->priv->actions != NULL); g_return_if_fail (application->priv->is_registered); - if (application->priv->is_remote) - g_application_impl_change_action_state (application->priv->impl, - action_name, value, - get_platform_data (application)); + 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, @@ -1379,12 +1506,12 @@ g_application_activate_action (GActionGroup *action_group, { GApplication *application = G_APPLICATION (action_group); + g_return_if_fail (application->priv->is_remote || + application->priv->actions != NULL); g_return_if_fail (application->priv->is_registered); - if (application->priv->is_remote) - g_application_impl_activate_action (application->priv->impl, - action_name, parameter, - get_platform_data (application)); + 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, @@ -1394,16 +1521,54 @@ g_application_activate_action (GActionGroup *action_group, 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 = 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: */