| /* | |
| * Copyright © 2010 Codethink Limited | |
| * | |
| * SPDX-License-Identifier: LGPL-2.1-or-later | |
| * | |
| * 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.1 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, see <http://www.gnu.org/licenses/>. | |
| * | |
| * Authors: Ryan Lortie <desrt@desrt.ca> | |
| */ | |
| /* Prologue {{{1 */ | |
| #include "config.h" | |
| #include "gapplication.h" | |
| #include "gapplicationcommandline.h" | |
| #include "gsimpleactiongroup.h" | |
| #include "gremoteactiongroup.h" | |
| #include "gapplicationimpl.h" | |
| #include "gactiongroup.h" | |
| #include "gactionmap.h" | |
| #include "gsettings.h" | |
| #include "gnotification-private.h" | |
| #include "gnotificationbackend.h" | |
| #include "gdbusutils.h" | |
| #include "gioenumtypes.h" | |
| #include "gioenums.h" | |
| #include "gfile.h" | |
| #include "glib-private.h" | |
| #include "glibintl.h" | |
| #include "gmarshal-internal.h" | |
| #include <string.h> | |
| /** | |
| * GApplication: | |
| * | |
| * `GApplication` is the core class for application support. | |
| * | |
| * A `GApplication` is the foundation of an application. It wraps some | |
| * low-level platform-specific services and is intended to act as the | |
| * foundation for higher-level application classes such as | |
| * `GtkApplication` or `MxApplication`. In general, you should not use | |
| * this class outside of a higher level framework. | |
| * | |
| * `GApplication` provides convenient life-cycle management by maintaining | |
| * a "use count" for the primary application instance. The use count can | |
| * be changed using [method@Gio.Application.hold] and | |
| * [method@Gio.Application.release]. If it drops to zero, the application | |
| * exits. Higher-level classes such as `GtkApplication` employ the use count | |
| * to ensure that the application stays alive as long as it has any opened | |
| * windows. | |
| * | |
| * Another feature that `GApplication` (optionally) provides is process | |
| * uniqueness. Applications can make use of this functionality by | |
| * providing a unique application ID. If given, only one application | |
| * with this ID can be running at a time per session. The session | |
| * concept is platform-dependent, but corresponds roughly to a graphical | |
| * desktop login. When your application is launched again, its | |
| * arguments are passed through platform communication to the already | |
| * running program. The already running instance of the program is | |
| * called the "primary instance"; for non-unique applications this is | |
| * always the current instance. On Linux, the D-Bus session bus | |
| * is used for communication. | |
| * | |
| * The use of `GApplication` differs from some other commonly-used | |
| * uniqueness libraries (such as libunique) in important ways. The | |
| * application is not expected to manually register itself and check | |
| * if it is the primary instance. Instead, the main() function of a | |
| * `GApplication` should do very little more than instantiating the | |
| * application instance, possibly connecting signal handlers, then | |
| * calling [method@Gio.Application.run]. All checks for uniqueness are done | |
| * internally. If the application is the primary instance then the | |
| * startup signal is emitted and the mainloop runs. If the application | |
| * is not the primary instance then a signal is sent to the primary | |
| * instance and [method@Gio.Application.run] promptly returns. See the code | |
| * examples below. | |
| * | |
| * If used, the expected form of an application identifier is the | |
| * same as that of a | |
| * [D-Bus well-known bus name](https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus). | |
| * Examples include: `com.example.MyApp`, `org.example.internal_apps.Calculator`, | |
| * `org._7_zip.Archiver`. | |
| * For details on valid application identifiers, see [func@Gio.Application.id_is_valid]. | |
| * | |
| * On Linux, the application identifier is claimed 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 | |
| * [method@Gio.Application.register]). Unfortunately, this means that you cannot | |
| * use [property@Gio.Application:is-remote] to decide if you want to register | |
| * object paths. | |
| * | |
| * `GApplication` also implements the [iface@Gio.ActionGroup] and [iface@Gio.ActionMap] | |
| * interfaces and lets you easily export actions by adding them with | |
| * [method@Gio.ActionMap.add_action]. When invoking an action by calling | |
| * [method@Gio.ActionGroup.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 [class@Gio.DBusActionGroup] wrapper to | |
| * conveniently access them remotely. GIO provides a [class@Gio.DBusMenuModel] wrapper | |
| * for remote access to exported [class@Gio.MenuModel]s. | |
| * | |
| * Note: Due to the fact that actions are exported on the session bus, | |
| * using `maybe` parameters is not supported, since D-Bus does not support | |
| * `maybe` types. | |
| * | |
| * 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 [signal@Gio.Application::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 | |
| * [struct@GLib.Variant] dictionary mapping strings to variants. To use platform | |
| * data, override the [vfunc@Gio.Application.before_emit] or | |
| * [vfunc@Gio.Application.after_emit] virtual functions | |
| * in your `GApplication` subclass. When dealing with | |
| * [class@Gio.ApplicationCommandLine] objects, the platform data is | |
| * directly available via [method@Gio.ApplicationCommandLine.get_cwd], | |
| * [method@Gio.ApplicationCommandLine.get_environ] and | |
| * [method@Gio.ApplicationCommandLine.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_ENVIRONMENT` flag is set. `GApplication` subclasses | |
| * can add their own platform data by overriding the | |
| * [vfunc@Gio.Application.add_platform_data] virtual function. For instance, | |
| * `GtkApplication` adds startup notification data in this way. | |
| * | |
| * To parse commandline arguments you may handle the | |
| * [signal@Gio.Application::command-line] signal or override the | |
| * [vfunc@Gio.Application.local_command_line] virtual function, to parse them in | |
| * either the primary instance or the local instance, respectively. | |
| * | |
| * For an example of opening files with a `GApplication`, see | |
| * [gapplication-example-open.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-open.c). | |
| * | |
| * For an example of using actions with `GApplication`, see | |
| * [gapplication-example-actions.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-actions.c). | |
| * | |
| * For an example of using extra D-Bus hooks with `GApplication`, see | |
| * [gapplication-example-dbushooks.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-dbushooks.c). | |
| * | |
| * Since: 2.28 | |
| */ | |
| /** | |
| * GApplicationClass: | |
| * @startup: invoked on the primary instance immediately after registration | |
| * @shutdown: invoked only on the registered primary instance immediately | |
| * after the main loop terminates | |
| * @activate: invoked on the primary instance when an activation occurs | |
| * @open: invoked on the primary instance when there are files to open | |
| * @command_line: invoked on the primary instance when a command-line is | |
| * not handled locally | |
| * @local_command_line: invoked (locally). The virtual function has the chance | |
| * to inspect (and possibly replace) command line arguments. See | |
| * g_application_run() for more information. Also see the | |
| * #GApplication::handle-local-options signal, which is a simpler | |
| * alternative to handling some commandline options locally | |
| * @before_emit: invoked on the primary instance before 'activate', 'open', | |
| * 'command-line' or any action invocation, gets the 'platform data' from | |
| * the calling instance | |
| * @after_emit: invoked on the primary instance after 'activate', 'open', | |
| * 'command-line' or any action invocation, gets the 'platform data' from | |
| * the calling instance | |
| * @add_platform_data: invoked (locally) to add 'platform data' to be sent to | |
| * the primary instance when activating, opening or invoking actions | |
| * @quit_mainloop: Used to be invoked on the primary instance when the use | |
| * count of the application drops to zero (and after any inactivity | |
| * timeout, if requested). Not used anymore since 2.32 | |
| * @run_mainloop: Used to be invoked on the primary instance from | |
| * g_application_run() if the use-count is non-zero. Since 2.32, | |
| * GApplication is iterating the main context directly and is not | |
| * using @run_mainloop anymore | |
| * @dbus_register: invoked locally during registration, if the application is | |
| * using its D-Bus backend. You can use this to export extra objects on the | |
| * bus, that need to exist before the application tries to own the bus name. | |
| * The function is passed the #GDBusConnection to to session bus, and the | |
| * object path that #GApplication will use to export its D-Bus API. | |
| * If this function returns %TRUE, registration will proceed; otherwise | |
| * registration will abort. Since: 2.34 | |
| * @dbus_unregister: invoked locally during unregistration, if the application | |
| * is using its D-Bus backend. Use this to undo anything done by | |
| * the @dbus_register vfunc. Since: 2.34 | |
| * @handle_local_options: invoked locally after the parsing of the commandline | |
| * options has occurred. Since: 2.40 | |
| * @name_lost: invoked when another instance is taking over the name. Since: 2.60 | |
| * | |
| * Virtual function table for #GApplication. | |
| * | |
| * Since: 2.28 | |
| */ | |
| struct _GApplicationPrivate | |
| { | |
| GApplicationFlags flags; | |
| gchar *id; | |
| gchar *version; | |
| gchar *resource_path; | |
| GActionGroup *actions; | |
| guint inactivity_timeout_id; | |
| guint inactivity_timeout; | |
| guint use_count; | |
| guint busy_count; | |
| guint is_registered : 1; | |
| guint is_remote : 1; | |
| guint did_startup : 1; | |
| guint did_shutdown : 1; | |
| guint must_quit_now : 1; | |
| GRemoteActionGroup *remote_actions; | |
| GApplicationImpl *impl; | |
| GNotificationBackend *notifications; | |
| /* GOptionContext support */ | |
| GOptionGroup *main_options; | |
| GSList *option_groups; | |
| GHashTable *packed_options; | |
| gboolean options_parsed; | |
| gchar *parameter_string; | |
| gchar *summary; | |
| gchar *description; | |
| /* Allocated option strings, from g_application_add_main_option() */ | |
| GSList *option_strings; | |
| }; | |
| enum | |
| { | |
| PROP_NONE, | |
| PROP_APPLICATION_ID, | |
| PROP_VERSION, | |
| PROP_FLAGS, | |
| PROP_RESOURCE_BASE_PATH, | |
| PROP_IS_REGISTERED, | |
| PROP_IS_REMOTE, | |
| PROP_INACTIVITY_TIMEOUT, | |
| PROP_ACTION_GROUP, | |
| PROP_IS_BUSY | |
| }; | |
| enum | |
| { | |
| SIGNAL_STARTUP, | |
| SIGNAL_SHUTDOWN, | |
| SIGNAL_ACTIVATE, | |
| SIGNAL_OPEN, | |
| SIGNAL_ACTION, | |
| SIGNAL_COMMAND_LINE, | |
| SIGNAL_HANDLE_LOCAL_OPTIONS, | |
| SIGNAL_NAME_LOST, | |
| NR_SIGNALS | |
| }; | |
| static guint g_application_signals[NR_SIGNALS]; | |
| static void g_application_action_group_iface_init (GActionGroupInterface *); | |
| static void g_application_action_map_iface_init (GActionMapInterface *); | |
| G_DEFINE_TYPE_WITH_CODE (GApplication, g_application, G_TYPE_OBJECT, | |
| G_ADD_PRIVATE (GApplication) | |
| G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_application_action_group_iface_init) | |
| G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_MAP, g_application_action_map_iface_init)) | |
| /* GApplicationExportedActions {{{1 */ | |
| /* We create a subclass of GSimpleActionGroup that implements | |
| * GRemoteActionGroup and deals with the platform data using | |
| * GApplication's before/after_emit vfuncs. This is the action group we | |
| * will be exporting. | |
| * | |
| * We could implement GRemoteActionGroup on GApplication directly, but | |
| * this would be potentially extremely confusing to have exposed as part | |
| * of the public API of GApplication. We certainly don't want anyone in | |
| * the same process to be calling these APIs... | |
| */ | |
| typedef GSimpleActionGroupClass GApplicationExportedActionsClass; | |
| typedef struct | |
| { | |
| GSimpleActionGroup parent_instance; | |
| GApplication *application; | |
| } GApplicationExportedActions; | |
| static GType g_application_exported_actions_get_type (void); | |
| static void g_application_exported_actions_iface_init (GRemoteActionGroupInterface *iface); | |
| G_DEFINE_TYPE_WITH_CODE (GApplicationExportedActions, g_application_exported_actions, G_TYPE_SIMPLE_ACTION_GROUP, | |
| G_IMPLEMENT_INTERFACE (G_TYPE_REMOTE_ACTION_GROUP, g_application_exported_actions_iface_init)) | |
| static void | |
| g_application_exported_actions_activate_action_full (GRemoteActionGroup *remote, | |
| const gchar *action_name, | |
| GVariant *parameter, | |
| GVariant *platform_data) | |
| { | |
| GApplicationExportedActions *exported = (GApplicationExportedActions *) remote; | |
| G_APPLICATION_GET_CLASS (exported->application) | |
| ->before_emit (exported->application, platform_data); | |
| g_action_group_activate_action (G_ACTION_GROUP (exported), action_name, parameter); | |
| G_APPLICATION_GET_CLASS (exported->application) | |
| ->after_emit (exported->application, platform_data); | |
| } | |
| static void | |
| g_application_exported_actions_change_action_state_full (GRemoteActionGroup *remote, | |
| const gchar *action_name, | |
| GVariant *value, | |
| GVariant *platform_data) | |
| { | |
| GApplicationExportedActions *exported = (GApplicationExportedActions *) remote; | |
| G_APPLICATION_GET_CLASS (exported->application) | |
| ->before_emit (exported->application, platform_data); | |
| g_action_group_change_action_state (G_ACTION_GROUP (exported), action_name, value); | |
| G_APPLICATION_GET_CLASS (exported->application) | |
| ->after_emit (exported->application, platform_data); | |
| } | |
| static void | |
| g_application_exported_actions_init (GApplicationExportedActions *actions) | |
| { | |
| } | |
| static void | |
| g_application_exported_actions_iface_init (GRemoteActionGroupInterface *iface) | |
| { | |
| iface->activate_action_full = g_application_exported_actions_activate_action_full; | |
| iface->change_action_state_full = g_application_exported_actions_change_action_state_full; | |
| } | |
| static void | |
| g_application_exported_actions_class_init (GApplicationExportedActionsClass *class) | |
| { | |
| } | |
| static GActionGroup * | |
| g_application_exported_actions_new (GApplication *application) | |
| { | |
| GApplicationExportedActions *actions; | |
| actions = g_object_new (g_application_exported_actions_get_type (), NULL); | |
| actions->application = application; | |
| return G_ACTION_GROUP (actions); | |
| } | |
| /* Command line option handling {{{1 */ | |
| static void | |
| free_option_entry (gpointer data) | |
| { | |
| GOptionEntry *entry = data; | |
| switch (entry->arg) | |
| { | |
| case G_OPTION_ARG_STRING: | |
| case G_OPTION_ARG_FILENAME: | |
| g_free (*(gchar **) entry->arg_data); | |
| break; | |
| case G_OPTION_ARG_STRING_ARRAY: | |
| case G_OPTION_ARG_FILENAME_ARRAY: | |
| g_strfreev (*(gchar ***) entry->arg_data); | |
| break; | |
| default: | |
| /* most things require no free... */ | |
| break; | |
| } | |
| /* ...except for the space that we allocated for it ourselves */ | |
| g_free (entry->arg_data); | |
| g_slice_free (GOptionEntry, entry); | |
| } | |
| static void | |
| g_application_pack_option_entries (GApplication *application, | |
| GVariantDict *dict) | |
| { | |
| GHashTableIter iter; | |
| gpointer item; | |
| g_hash_table_iter_init (&iter, application->priv->packed_options); | |
| while (g_hash_table_iter_next (&iter, NULL, &item)) | |
| { | |
| GOptionEntry *entry = item; | |
| GVariant *value = NULL; | |
| switch (entry->arg) | |
| { | |
| case G_OPTION_ARG_NONE: | |
| if (*(gboolean *) entry->arg_data != 2) | |
| value = g_variant_new_boolean (*(gboolean *) entry->arg_data); | |
| break; | |
| case G_OPTION_ARG_STRING: | |
| if (*(gchar **) entry->arg_data) | |
| value = g_variant_new_string (*(gchar **) entry->arg_data); | |
| break; | |
| case G_OPTION_ARG_INT: | |
| if (*(gint32 *) entry->arg_data) | |
| value = g_variant_new_int32 (*(gint32 *) entry->arg_data); | |
| break; | |
| case G_OPTION_ARG_FILENAME: | |
| if (*(gchar **) entry->arg_data) | |
| value = g_variant_new_bytestring (*(gchar **) entry->arg_data); | |
| break; | |
| case G_OPTION_ARG_STRING_ARRAY: | |
| if (*(gchar ***) entry->arg_data) | |
| value = g_variant_new_strv (*(const gchar ***) entry->arg_data, -1); | |
| break; | |
| case G_OPTION_ARG_FILENAME_ARRAY: | |
| if (*(gchar ***) entry->arg_data) | |
| value = g_variant_new_bytestring_array (*(const gchar ***) entry->arg_data, -1); | |
| break; | |
| case G_OPTION_ARG_DOUBLE: | |
| if (*(gdouble *) entry->arg_data) | |
| value = g_variant_new_double (*(gdouble *) entry->arg_data); | |
| break; | |
| case G_OPTION_ARG_INT64: | |
| if (*(gint64 *) entry->arg_data) | |
| value = g_variant_new_int64 (*(gint64 *) entry->arg_data); | |
| break; | |
| default: | |
| g_assert_not_reached (); | |
| } | |
| if (value) | |
| g_variant_dict_insert_value (dict, entry->long_name, value); | |
| } | |
| } | |
| static GVariantDict * | |
| g_application_parse_command_line (GApplication *application, | |
| gchar ***arguments, | |
| gboolean *print_version, | |
| GError **error) | |
| { | |
| gboolean become_service = FALSE; | |
| gchar *app_id = NULL; | |
| gboolean replace = FALSE; | |
| gboolean version = FALSE; | |
| GVariantDict *dict = NULL; | |
| GOptionContext *context; | |
| GOptionGroup *gapplication_group; | |
| /* Due to the memory management of GOptionGroup we can only parse | |
| * options once. That's because once you add a group to the | |
| * GOptionContext there is no way to get it back again. This is fine: | |
| * local_command_line() should never get invoked more than once | |
| * anyway. Add a sanity check just to be sure. | |
| */ | |
| g_return_val_if_fail (!application->priv->options_parsed, NULL); | |
| context = g_option_context_new (application->priv->parameter_string); | |
| g_option_context_set_summary (context, application->priv->summary); | |
| g_option_context_set_description (context, application->priv->description); | |
| gapplication_group = g_option_group_new ("gapplication", | |
| _("GApplication Options:"), _("Show GApplication options"), | |
| NULL, NULL); | |
| g_option_group_set_translation_domain (gapplication_group, GETTEXT_PACKAGE); | |
| g_option_context_add_group (context, gapplication_group); | |
| /* If the application has not registered local options and it has | |
| * G_APPLICATION_HANDLES_COMMAND_LINE then we have to assume that | |
| * their primary instance commandline handler may want to deal with | |
| * the arguments. We must therefore ignore them. | |
| * | |
| * We must also ignore --help in this case since some applications | |
| * will try to handle this from the remote side. See #737869. | |
| */ | |
| if (application->priv->main_options == NULL && (application->priv->flags & G_APPLICATION_HANDLES_COMMAND_LINE)) | |
| { | |
| g_option_context_set_ignore_unknown_options (context, TRUE); | |
| g_option_context_set_help_enabled (context, FALSE); | |
| } | |
| /* Add the main option group, if it exists */ | |
| if (application->priv->main_options) | |
| { | |
| /* This consumes the main_options */ | |
| g_option_context_set_main_group (context, application->priv->main_options); | |
| application->priv->main_options = NULL; | |
| } | |
| /* Add any other option groups if they exist. Adding them to the | |
| * context will consume them, so we free the list as we go... | |
| */ | |
| while (application->priv->option_groups) | |
| { | |
| g_option_context_add_group (context, application->priv->option_groups->data); | |
| application->priv->option_groups = g_slist_delete_link (application->priv->option_groups, | |
| application->priv->option_groups); | |
| } | |
| /* In the case that we are not explicitly marked as a service or a | |
| * launcher then we want to add the "--gapplication-service" option to | |
| * allow the process to be made into a service. | |
| */ | |
| if ((application->priv->flags & (G_APPLICATION_IS_SERVICE | G_APPLICATION_IS_LAUNCHER)) == 0) | |
| { | |
| GOptionEntry entries[] = { | |
| { "gapplication-service", '\0', 0, G_OPTION_ARG_NONE, &become_service, | |
| N_("Enter GApplication service mode (use from D-Bus service files)"), NULL }, | |
| G_OPTION_ENTRY_NULL | |
| }; | |
| g_option_group_add_entries (gapplication_group, entries); | |
| } | |
| /* Allow overriding the ID if the application allows it */ | |
| if (application->priv->flags & G_APPLICATION_CAN_OVERRIDE_APP_ID) | |
| { | |
| GOptionEntry entries[] = { | |
| { "gapplication-app-id", '\0', 0, G_OPTION_ARG_STRING, &app_id, | |
| N_("Override the application’s ID"), NULL }, | |
| G_OPTION_ENTRY_NULL | |
| }; | |
| g_option_group_add_entries (gapplication_group, entries); | |
| } | |
| if (application->priv->version) | |
| { | |
| GOptionEntry entries[] = { | |
| { "version", '\0', 0, G_OPTION_ARG_NONE, &version, | |
| N_("Print the application version"), NULL }, | |
| G_OPTION_ENTRY_NULL | |
| }; | |
| g_option_group_add_entries (gapplication_group, entries); | |
| } | |
| /* Allow replacing if the application allows it */ | |
| if (application->priv->flags & G_APPLICATION_ALLOW_REPLACEMENT) | |
| { | |
| GOptionEntry entries[] = { | |
| { "gapplication-replace", '\0', 0, G_OPTION_ARG_NONE, &replace, | |
| N_("Replace the running instance"), NULL }, | |
| G_OPTION_ENTRY_NULL | |
| }; | |
| g_option_group_add_entries (gapplication_group, entries); | |
| } | |
| /* Now we parse... */ | |
| if (!g_option_context_parse_strv (context, arguments, error)) | |
| goto out; | |
| *print_version = version; | |
| /* Check for --gapplication-service */ | |
| if (become_service) | |
| application->priv->flags |= G_APPLICATION_IS_SERVICE; | |
| /* Check for --gapplication-app-id */ | |
| if (app_id) | |
| g_application_set_application_id (application, app_id); | |
| /* Check for --gapplication-replace */ | |
| if (replace) | |
| application->priv->flags |= G_APPLICATION_REPLACE; | |
| dict = g_variant_dict_new (NULL); | |
| if (application->priv->packed_options) | |
| { | |
| g_application_pack_option_entries (application, dict); | |
| g_hash_table_unref (application->priv->packed_options); | |
| application->priv->packed_options = NULL; | |
| } | |
| out: | |
| /* Make sure we don't run again */ | |
| application->priv->options_parsed = TRUE; | |
| g_option_context_free (context); | |
| g_free (app_id); | |
| return dict; | |
| } | |
| static void | |
| add_packed_option (GApplication *application, | |
| GOptionEntry *entry) | |
| { | |
| switch (entry->arg) | |
| { | |
| case G_OPTION_ARG_NONE: | |
| entry->arg_data = g_new (gboolean, 1); | |
| *(gboolean *) entry->arg_data = 2; | |
| break; | |
| case G_OPTION_ARG_INT: | |
| entry->arg_data = g_new0 (gint, 1); | |
| break; | |
| case G_OPTION_ARG_STRING: | |
| case G_OPTION_ARG_FILENAME: | |
| case G_OPTION_ARG_STRING_ARRAY: | |
| case G_OPTION_ARG_FILENAME_ARRAY: | |
| entry->arg_data = g_new0 (gpointer, 1); | |
| break; | |
| case G_OPTION_ARG_INT64: | |
| entry->arg_data = g_new0 (gint64, 1); | |
| break; | |
| case G_OPTION_ARG_DOUBLE: | |
| entry->arg_data = g_new0 (gdouble, 1); | |
| break; | |
| default: | |
| g_return_if_reached (); | |
| } | |
| if (!application->priv->packed_options) | |
| application->priv->packed_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_option_entry); | |
| g_hash_table_insert (application->priv->packed_options, | |
| g_strdup (entry->long_name), | |
| g_slice_dup (GOptionEntry, entry)); | |
| } | |
| /** | |
| * g_application_add_main_option_entries: | |
| * @application: a #GApplication | |
| * @entries: (array zero-terminated=1) (element-type GOptionEntry): the | |
| * main options for the application | |
| * | |
| * Adds main option entries to be handled by @application. | |
| * | |
| * This function is comparable to g_option_context_add_main_entries(). | |
| * | |
| * After the commandline arguments are parsed, the | |
| * #GApplication::handle-local-options signal will be emitted. At this | |
| * point, the application can inspect the values pointed to by @arg_data | |
| * in the given #GOptionEntrys. | |
| * | |
| * Unlike #GOptionContext, #GApplication supports giving a %NULL | |
| * @arg_data for a non-callback #GOptionEntry. This results in the | |
| * argument in question being packed into a #GVariantDict which is also | |
| * passed to #GApplication::handle-local-options, where it can be | |
| * inspected and modified. If %G_APPLICATION_HANDLES_COMMAND_LINE is | |
| * set, then the resulting dictionary is sent to the primary instance, | |
| * where g_application_command_line_get_options_dict() will return it. | |
| * As it has been passed outside the process at this point, the types of all | |
| * values in the options dict must be checked before being used. | |
| * This "packing" is done according to the type of the argument -- | |
| * booleans for normal flags, strings for strings, bytestrings for | |
| * filenames, etc. The packing only occurs if the flag is given (ie: we | |
| * do not pack a "false" #GVariant in the case that a flag is missing). | |
| * | |
| * In general, it is recommended that all commandline arguments are | |
| * parsed locally. The options dictionary should then be used to | |
| * transmit the result of the parsing to the primary instance, where | |
| * g_variant_dict_lookup() can be used. For local options, it is | |
| * possible to either use @arg_data in the usual way, or to consult (and | |
| * potentially remove) the option from the options dictionary. | |
| * | |
| * This function is new in GLib 2.40. Before then, the only real choice | |
| * was to send all of the commandline arguments (options and all) to the | |
| * primary instance for handling. #GApplication ignored them completely | |
| * on the local side. Calling this function "opts in" to the new | |
| * behaviour, and in particular, means that unrecognized options will be | |
| * treated as errors. Unrecognized options have never been ignored when | |
| * %G_APPLICATION_HANDLES_COMMAND_LINE is unset. | |
| * | |
| * If #GApplication::handle-local-options needs to see the list of | |
| * filenames, then the use of %G_OPTION_REMAINING is recommended. If | |
| * @arg_data is %NULL then %G_OPTION_REMAINING can be used as a key into | |
| * the options dictionary. If you do use %G_OPTION_REMAINING then you | |
| * need to handle these arguments for yourself because once they are | |
| * consumed, they will no longer be visible to the default handling | |
| * (which treats them as filenames to be opened). | |
| * | |
| * It is important to use the proper GVariant format when retrieving | |
| * the options with g_variant_dict_lookup(): | |
| * - for %G_OPTION_ARG_NONE, use `b` | |
| * - for %G_OPTION_ARG_STRING, use `&s` | |
| * - for %G_OPTION_ARG_INT, use `i` | |
| * - for %G_OPTION_ARG_INT64, use `x` | |
| * - for %G_OPTION_ARG_DOUBLE, use `d` | |
| * - for %G_OPTION_ARG_FILENAME, use `^&ay` | |
| * - for %G_OPTION_ARG_STRING_ARRAY, use `^a&s` | |
| * - for %G_OPTION_ARG_FILENAME_ARRAY, use `^a&ay` | |
| * | |
| * Since: 2.40 | |
| */ | |
| void | |
| g_application_add_main_option_entries (GApplication *application, | |
| const GOptionEntry *entries) | |
| { | |
| gint i; | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (entries != NULL); | |
| if (!application->priv->main_options) | |
| { | |
| application->priv->main_options = g_option_group_new (NULL, NULL, NULL, NULL, NULL); | |
| g_option_group_set_translation_domain (application->priv->main_options, NULL); | |
| } | |
| for (i = 0; entries[i].long_name; i++) | |
| { | |
| GOptionEntry my_entries[2] = | |
| { | |
| G_OPTION_ENTRY_NULL, | |
| G_OPTION_ENTRY_NULL | |
| }; | |
| my_entries[0] = entries[i]; | |
| if (!my_entries[0].arg_data) | |
| add_packed_option (application, &my_entries[0]); | |
| g_option_group_add_entries (application->priv->main_options, my_entries); | |
| } | |
| } | |
| /** | |
| * g_application_add_main_option: | |
| * @application: the #GApplication | |
| * @long_name: the long name of an option used to specify it in a commandline | |
| * @short_name: the short name of an option | |
| * @flags: flags from #GOptionFlags | |
| * @arg: the type of the option, as a #GOptionArg | |
| * @description: the description for the option in `--help` output | |
| * @arg_description: (nullable): the placeholder to use for the extra argument | |
| * parsed by the option in `--help` output | |
| * | |
| * Add an option to be handled by @application. | |
| * | |
| * Calling this function is the equivalent of calling | |
| * g_application_add_main_option_entries() with a single #GOptionEntry | |
| * that has its arg_data member set to %NULL. | |
| * | |
| * The parsed arguments will be packed into a #GVariantDict which | |
| * is passed to #GApplication::handle-local-options. If | |
| * %G_APPLICATION_HANDLES_COMMAND_LINE is set, then it will also | |
| * be sent to the primary instance. See | |
| * g_application_add_main_option_entries() for more details. | |
| * | |
| * See #GOptionEntry for more documentation of the arguments. | |
| * | |
| * Since: 2.42 | |
| **/ | |
| void | |
| g_application_add_main_option (GApplication *application, | |
| const char *long_name, | |
| char short_name, | |
| GOptionFlags flags, | |
| GOptionArg arg, | |
| const char *description, | |
| const char *arg_description) | |
| { | |
| gchar *dup_string; | |
| GOptionEntry my_entry[2] = { | |
| { NULL, short_name, flags, arg, NULL, NULL, NULL }, | |
| G_OPTION_ENTRY_NULL | |
| }; | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (long_name != NULL); | |
| g_return_if_fail (description != NULL); | |
| my_entry[0].long_name = dup_string = g_strdup (long_name); | |
| application->priv->option_strings = g_slist_prepend (application->priv->option_strings, dup_string); | |
| my_entry[0].description = dup_string = g_strdup (description); | |
| application->priv->option_strings = g_slist_prepend (application->priv->option_strings, dup_string); | |
| my_entry[0].arg_description = dup_string = g_strdup (arg_description); | |
| application->priv->option_strings = g_slist_prepend (application->priv->option_strings, dup_string); | |
| g_application_add_main_option_entries (application, my_entry); | |
| } | |
| /** | |
| * g_application_add_option_group: | |
| * @application: the #GApplication | |
| * @group: (transfer full): a #GOptionGroup | |
| * | |
| * Adds a #GOptionGroup to the commandline handling of @application. | |
| * | |
| * This function is comparable to g_option_context_add_group(). | |
| * | |
| * Unlike g_application_add_main_option_entries(), this function does | |
| * not deal with %NULL @arg_data and never transmits options to the | |
| * primary instance. | |
| * | |
| * The reason for that is because, by the time the options arrive at the | |
| * primary instance, it is typically too late to do anything with them. | |
| * Taking the GTK option group as an example: GTK will already have been | |
| * initialised by the time the #GApplication::command-line handler runs. | |
| * In the case that this is not the first-running instance of the | |
| * application, the existing instance may already have been running for | |
| * a very long time. | |
| * | |
| * This means that the options from #GOptionGroup are only really usable | |
| * in the case that the instance of the application being run is the | |
| * first instance. Passing options like `--display=` or `--gdk-debug=` | |
| * on future runs will have no effect on the existing primary instance. | |
| * | |
| * Calling this function will cause the options in the supplied option | |
| * group to be parsed, but it does not cause you to be "opted in" to the | |
| * new functionality whereby unrecognized options are rejected even if | |
| * %G_APPLICATION_HANDLES_COMMAND_LINE was given. | |
| * | |
| * Since: 2.40 | |
| **/ | |
| void | |
| g_application_add_option_group (GApplication *application, | |
| GOptionGroup *group) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (group != NULL); | |
| application->priv->option_groups = g_slist_prepend (application->priv->option_groups, group); | |
| } | |
| /** | |
| * g_application_set_option_context_parameter_string: | |
| * @application: the #GApplication | |
| * @parameter_string: (nullable): a string which is displayed | |
| * in the first line of `--help` output, after the usage summary `programname [OPTION...]`. | |
| * | |
| * Sets the parameter string to be used by the commandline handling of @application. | |
| * | |
| * This function registers the argument to be passed to g_option_context_new() | |
| * when the internal #GOptionContext of @application is created. | |
| * | |
| * See g_option_context_new() for more information about @parameter_string. | |
| * | |
| * Since: 2.56 | |
| */ | |
| void | |
| g_application_set_option_context_parameter_string (GApplication *application, | |
| const gchar *parameter_string) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_free (application->priv->parameter_string); | |
| application->priv->parameter_string = g_strdup (parameter_string); | |
| } | |
| /** | |
| * g_application_set_option_context_summary: | |
| * @application: the #GApplication | |
| * @summary: (nullable): a string to be shown in `--help` output | |
| * before the list of options, or %NULL | |
| * | |
| * Adds a summary to the @application option context. | |
| * | |
| * See g_option_context_set_summary() for more information. | |
| * | |
| * Since: 2.56 | |
| */ | |
| void | |
| g_application_set_option_context_summary (GApplication *application, | |
| const gchar *summary) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_free (application->priv->summary); | |
| application->priv->summary = g_strdup (summary); | |
| } | |
| /** | |
| * g_application_set_option_context_description: | |
| * @application: the #GApplication | |
| * @description: (nullable): a string to be shown in `--help` output | |
| * after the list of options, or %NULL | |
| * | |
| * Adds a description to the @application option context. | |
| * | |
| * See g_option_context_set_description() for more information. | |
| * | |
| * Since: 2.56 | |
| */ | |
| void | |
| g_application_set_option_context_description (GApplication *application, | |
| const gchar *description) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_free (application->priv->description); | |
| application->priv->description = g_strdup (description); | |
| } | |
| /* vfunc defaults {{{1 */ | |
| static void | |
| g_application_real_before_emit (GApplication *application, | |
| GVariant *platform_data) | |
| { | |
| } | |
| static void | |
| g_application_real_after_emit (GApplication *application, | |
| GVariant *platform_data) | |
| { | |
| } | |
| 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 | |
| g_application_real_activate (GApplication *application) | |
| { | |
| if (!g_signal_has_handler_pending (application, | |
| g_application_signals[SIGNAL_ACTIVATE], | |
| 0, TRUE) && | |
| G_APPLICATION_GET_CLASS (application)->activate == g_application_real_activate) | |
| { | |
| static gboolean warned; | |
| if (warned) | |
| return; | |
| g_warning ("Your application does not implement " | |
| "g_application_activate() and has no handlers connected " | |
| "to the 'activate' signal. It should do one of these."); | |
| warned = TRUE; | |
| } | |
| } | |
| static void | |
| g_application_real_open (GApplication *application, | |
| GFile **files, | |
| gint n_files, | |
| const gchar *hint) | |
| { | |
| if (!g_signal_has_handler_pending (application, | |
| g_application_signals[SIGNAL_OPEN], | |
| 0, TRUE) && | |
| G_APPLICATION_GET_CLASS (application)->open == g_application_real_open) | |
| { | |
| static gboolean warned; | |
| if (warned) | |
| return; | |
| g_warning ("Your application claims to support opening files " | |
| "but does not implement g_application_open() and has no " | |
| "handlers connected to the 'open' signal."); | |
| warned = TRUE; | |
| } | |
| } | |
| static int | |
| g_application_real_command_line (GApplication *application, | |
| GApplicationCommandLine *cmdline) | |
| { | |
| 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; | |
| 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; | |
| } | |
| return 1; | |
| } | |
| static gint | |
| g_application_real_handle_local_options (GApplication *application, | |
| GVariantDict *options) | |
| { | |
| return -1; | |
| } | |
| static GVariant * | |
| get_platform_data (GApplication *application, | |
| GVariant *options) | |
| { | |
| GVariantBuilder *builder; | |
| GVariant *result; | |
| builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); | |
| { | |
| gchar *cwd = g_get_current_dir (); | |
| g_variant_builder_add (builder, "{sv}", "cwd", | |
| g_variant_new_bytestring (cwd)); | |
| 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); | |
| } | |
| if (options) | |
| g_variant_builder_add (builder, "{sv}", "options", options); | |
| G_APPLICATION_GET_CLASS (application)-> | |
| add_platform_data (application, builder); | |
| result = g_variant_builder_end (builder); | |
| g_variant_builder_unref (builder); | |
| return result; | |
| } | |
| static void | |
| g_application_call_command_line (GApplication *application, | |
| const gchar * const *arguments, | |
| GVariant *options, | |
| gint *exit_status) | |
| { | |
| if (application->priv->is_remote) | |
| { | |
| GVariant *platform_data; | |
| platform_data = get_platform_data (application, options); | |
| *exit_status = g_application_impl_command_line (application->priv->impl, arguments, platform_data); | |
| } | |
| else | |
| { | |
| GApplicationCommandLine *cmdline; | |
| GVariant *v; | |
| gint handler_exit_status; | |
| v = g_variant_new_bytestring_array ((const gchar **) arguments, -1); | |
| cmdline = g_object_new (G_TYPE_APPLICATION_COMMAND_LINE, | |
| "arguments", v, | |
| "options", options, | |
| NULL); | |
| g_signal_emit (application, g_application_signals[SIGNAL_COMMAND_LINE], 0, cmdline, &handler_exit_status); | |
| /* For consistency with remote invocations */ | |
| g_application_command_line_set_exit_status (cmdline, handler_exit_status); | |
| *exit_status = g_application_command_line_get_exit_status (cmdline); | |
| g_object_unref (cmdline); | |
| } | |
| } | |
| static gboolean | |
| g_application_real_local_command_line (GApplication *application, | |
| gchar ***arguments, | |
| int *exit_status) | |
| { | |
| GError *error = NULL; | |
| GVariantDict *options; | |
| gint n_args; | |
| gboolean print_version = FALSE; | |
| options = g_application_parse_command_line (application, arguments, &print_version, &error); | |
| if (!options) | |
| { | |
| g_printerr ("%s\n", error->message); | |
| g_error_free (error); | |
| *exit_status = 1; | |
| return TRUE; | |
| } | |
| /* Exit quickly with --version? */ | |
| if (print_version) | |
| { | |
| const char *prgname = g_get_prgname (); | |
| g_assert (application->priv->version != NULL); | |
| if (prgname != NULL) | |
| g_print ("%s %s\n", prgname, application->priv->version); | |
| else | |
| g_print ("%s\n", application->priv->version); | |
| *exit_status = EXIT_SUCCESS; | |
| return TRUE; | |
| } | |
| g_signal_emit (application, g_application_signals[SIGNAL_HANDLE_LOCAL_OPTIONS], 0, options, exit_status); | |
| if (*exit_status >= 0) | |
| { | |
| g_variant_dict_unref (options); | |
| return TRUE; | |
| } | |
| if (!g_application_register (application, NULL, &error)) | |
| { | |
| g_printerr ("Failed to register: %s\n", error->message); | |
| g_variant_dict_unref (options); | |
| g_error_free (error); | |
| *exit_status = 1; | |
| return TRUE; | |
| } | |
| n_args = g_strv_length (*arguments); | |
| if (application->priv->flags & G_APPLICATION_IS_SERVICE) | |
| { | |
| if ((*exit_status = n_args > 1)) | |
| { | |
| g_printerr ("GApplication service mode takes no arguments.\n"); | |
| application->priv->flags &= ~G_APPLICATION_IS_SERVICE; | |
| *exit_status = 1; | |
| } | |
| else | |
| *exit_status = 0; | |
| } | |
| else if (application->priv->flags & G_APPLICATION_HANDLES_COMMAND_LINE) | |
| { | |
| g_application_call_command_line (application, | |
| (const gchar **) *arguments, | |
| g_variant_dict_end (options), | |
| exit_status); | |
| } | |
| else | |
| { | |
| if (n_args <= 1) | |
| { | |
| g_application_activate (application); | |
| *exit_status = 0; | |
| } | |
| else | |
| { | |
| if (~application->priv->flags & G_APPLICATION_HANDLES_OPEN) | |
| { | |
| g_critical ("This application can not open files."); | |
| *exit_status = 1; | |
| } | |
| else | |
| { | |
| GFile **files; | |
| gint n_files; | |
| gint i; | |
| n_files = n_args - 1; | |
| files = g_new (GFile *, n_files); | |
| for (i = 0; i < n_files; i++) | |
| files[i] = g_file_new_for_commandline_arg ((*arguments)[i + 1]); | |
| g_application_open (application, files, n_files, ""); | |
| for (i = 0; i < n_files; i++) | |
| g_object_unref (files[i]); | |
| g_free (files); | |
| *exit_status = 0; | |
| } | |
| } | |
| } | |
| g_variant_dict_unref (options); | |
| return TRUE; | |
| } | |
| static void | |
| g_application_real_add_platform_data (GApplication *application, | |
| GVariantBuilder *builder) | |
| { | |
| } | |
| static gboolean | |
| g_application_real_dbus_register (GApplication *application, | |
| GDBusConnection *connection, | |
| const gchar *object_path, | |
| GError **error) | |
| { | |
| return TRUE; | |
| } | |
| static void | |
| g_application_real_dbus_unregister (GApplication *application, | |
| GDBusConnection *connection, | |
| const gchar *object_path) | |
| { | |
| } | |
| static gboolean | |
| g_application_real_name_lost (GApplication *application) | |
| { | |
| g_application_quit (application); | |
| return TRUE; | |
| } | |
| /* GObject implementation stuff {{{1 */ | |
| static void | |
| g_application_set_property (GObject *object, | |
| guint prop_id, | |
| const GValue *value, | |
| GParamSpec *pspec) | |
| { | |
| GApplication *application = G_APPLICATION (object); | |
| switch (prop_id) | |
| { | |
| case PROP_APPLICATION_ID: | |
| g_application_set_application_id (application, | |
| g_value_get_string (value)); | |
| break; | |
| case PROP_VERSION: | |
| g_application_set_version (application, g_value_get_string (value)); | |
| break; | |
| case PROP_FLAGS: | |
| g_application_set_flags (application, g_value_get_flags (value)); | |
| break; | |
| case PROP_RESOURCE_BASE_PATH: | |
| g_application_set_resource_base_path (application, g_value_get_string (value)); | |
| break; | |
| case PROP_INACTIVITY_TIMEOUT: | |
| g_application_set_inactivity_timeout (application, | |
| g_value_get_uint (value)); | |
| break; | |
| case PROP_ACTION_GROUP: | |
| g_clear_object (&application->priv->actions); | |
| application->priv->actions = g_value_dup_object (value); | |
| break; | |
| default: | |
| g_assert_not_reached (); | |
| } | |
| } | |
| /** | |
| * g_application_set_action_group: | |
| * @application: a #GApplication | |
| * @action_group: (nullable): a #GActionGroup, or %NULL | |
| * | |
| * This used to be how actions were associated with a #GApplication. | |
| * Now there is #GActionMap for that. | |
| * | |
| * Since: 2.28 | |
| * | |
| * Deprecated:2.32:Use the #GActionMap interface instead. Never ever | |
| * mix use of this API with use of #GActionMap on the same @application | |
| * or things will go very badly wrong. This function is known to | |
| * introduce buggy behaviour (ie: signals not emitted on changes to the | |
| * action group), so you should really use #GActionMap instead. | |
| **/ | |
| void | |
| 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); | |
| if (application->priv->actions != NULL) | |
| g_object_unref (application->priv->actions); | |
| application->priv->actions = action_group; | |
| if (application->priv->actions != NULL) | |
| g_object_ref (application->priv->actions); | |
| } | |
| static void | |
| g_application_get_property (GObject *object, | |
| guint prop_id, | |
| GValue *value, | |
| GParamSpec *pspec) | |
| { | |
| GApplication *application = G_APPLICATION (object); | |
| switch (prop_id) | |
| { | |
| case PROP_APPLICATION_ID: | |
| g_value_set_string (value, | |
| g_application_get_application_id (application)); | |
| break; | |
| case PROP_VERSION: | |
| g_value_set_string (value, | |
| g_application_get_version (application)); | |
| break; | |
| case PROP_FLAGS: | |
| g_value_set_flags (value, | |
| g_application_get_flags (application)); | |
| break; | |
| case PROP_RESOURCE_BASE_PATH: | |
| g_value_set_string (value, g_application_get_resource_base_path (application)); | |
| break; | |
| case PROP_IS_REGISTERED: | |
| g_value_set_boolean (value, | |
| g_application_get_is_registered (application)); | |
| break; | |
| case PROP_IS_REMOTE: | |
| g_value_set_boolean (value, | |
| g_application_get_is_remote (application)); | |
| break; | |
| case PROP_INACTIVITY_TIMEOUT: | |
| g_value_set_uint (value, | |
| g_application_get_inactivity_timeout (application)); | |
| break; | |
| case PROP_IS_BUSY: | |
| g_value_set_boolean (value, g_application_get_is_busy (application)); | |
| break; | |
| default: | |
| g_assert_not_reached (); | |
| } | |
| } | |
| static void | |
| g_application_constructed (GObject *object) | |
| { | |
| GApplication *application = G_APPLICATION (object); | |
| if (g_application_get_default () == NULL) | |
| g_application_set_default (application); | |
| /* People should not set properties from _init... */ | |
| g_assert (application->priv->resource_path == NULL); | |
| if (application->priv->id != NULL) | |
| { | |
| gint i; | |
| application->priv->resource_path = g_strconcat ("/", application->priv->id, NULL); | |
| for (i = 1; application->priv->resource_path[i]; i++) | |
| if (application->priv->resource_path[i] == '.') | |
| application->priv->resource_path[i] = '/'; | |
| } | |
| } | |
| static void | |
| g_application_dispose (GObject *object) | |
| { | |
| GApplication *application = G_APPLICATION (object); | |
| if (application->priv->impl != NULL && | |
| G_APPLICATION_GET_CLASS (application)->dbus_unregister != g_application_real_dbus_unregister) | |
| { | |
| static gboolean warned; | |
| if (!warned) | |
| { | |
| g_warning ("Your application did not unregister from D-Bus before destruction. " | |
| "Consider using g_application_run()."); | |
| } | |
| warned = TRUE; | |
| } | |
| G_OBJECT_CLASS (g_application_parent_class)->dispose (object); | |
| } | |
| static void | |
| g_application_finalize (GObject *object) | |
| { | |
| GApplication *application = G_APPLICATION (object); | |
| if (application->priv->inactivity_timeout_id) | |
| g_source_remove (application->priv->inactivity_timeout_id); | |
| g_slist_free_full (application->priv->option_groups, (GDestroyNotify) g_option_group_unref); | |
| if (application->priv->main_options) | |
| g_option_group_unref (application->priv->main_options); | |
| if (application->priv->packed_options) | |
| g_hash_table_unref (application->priv->packed_options); | |
| g_free (application->priv->parameter_string); | |
| g_free (application->priv->summary); | |
| g_free (application->priv->description); | |
| g_free (application->priv->version); | |
| g_slist_free_full (application->priv->option_strings, g_free); | |
| if (application->priv->impl) | |
| g_application_impl_destroy (application->priv->impl); | |
| g_free (application->priv->id); | |
| if (g_application_get_default () == application) | |
| g_application_set_default (NULL); | |
| if (application->priv->actions) | |
| g_object_unref (application->priv->actions); | |
| g_clear_object (&application->priv->remote_actions); | |
| if (application->priv->notifications) | |
| g_object_unref (application->priv->notifications); | |
| g_free (application->priv->resource_path); | |
| G_OBJECT_CLASS (g_application_parent_class) | |
| ->finalize (object); | |
| } | |
| static void | |
| g_application_init (GApplication *application) | |
| { | |
| application->priv = g_application_get_instance_private (application); | |
| application->priv->actions = g_application_exported_actions_new (application); | |
| /* application->priv->actions is the one and only ref on the group, so when | |
| * we dispose, the action group will die, disconnecting all signals. | |
| */ | |
| g_signal_connect_swapped (application->priv->actions, "action-added", | |
| G_CALLBACK (g_action_group_action_added), application); | |
| g_signal_connect_swapped (application->priv->actions, "action-enabled-changed", | |
| G_CALLBACK (g_action_group_action_enabled_changed), application); | |
| g_signal_connect_swapped (application->priv->actions, "action-state-changed", | |
| G_CALLBACK (g_action_group_action_state_changed), application); | |
| g_signal_connect_swapped (application->priv->actions, "action-removed", | |
| G_CALLBACK (g_action_group_action_removed), application); | |
| } | |
| static gboolean | |
| g_application_handle_local_options_accumulator (GSignalInvocationHint *ihint, | |
| GValue *return_accu, | |
| const GValue *handler_return, | |
| gpointer dummy) | |
| { | |
| gint value; | |
| value = g_value_get_int (handler_return); | |
| g_value_set_int (return_accu, value); | |
| return value < 0; | |
| } | |
| static void | |
| g_application_class_init (GApplicationClass *class) | |
| { | |
| GObjectClass *object_class = G_OBJECT_CLASS (class); | |
| object_class->constructed = g_application_constructed; | |
| object_class->dispose = g_application_dispose; | |
| object_class->finalize = g_application_finalize; | |
| object_class->get_property = g_application_get_property; | |
| object_class->set_property = g_application_set_property; | |
| 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->handle_local_options = g_application_real_handle_local_options; | |
| class->add_platform_data = g_application_real_add_platform_data; | |
| class->dbus_register = g_application_real_dbus_register; | |
| class->dbus_unregister = g_application_real_dbus_unregister; | |
| class->name_lost = g_application_real_name_lost; | |
| /** | |
| * GApplication:application-id: | |
| * | |
| * The unique identifier for the application. | |
| * | |
| * Since: 2.28 | |
| */ | |
| g_object_class_install_property (object_class, PROP_APPLICATION_ID, | |
| g_param_spec_string ("application-id", NULL, NULL, | |
| NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | | |
| G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication:version: | |
| * | |
| * The human-readable version number of the application. | |
| * | |
| * Since: 2.80 | |
| */ | |
| g_object_class_install_property (object_class, PROP_VERSION, | |
| g_param_spec_string ("version", NULL, NULL, | |
| NULL, G_PARAM_READWRITE | | |
| G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY)); | |
| /** | |
| * GApplication:flags: | |
| * | |
| * Flags specifying the behaviour of the application. | |
| * | |
| * Since: 2.28 | |
| */ | |
| g_object_class_install_property (object_class, PROP_FLAGS, | |
| g_param_spec_flags ("flags", NULL, NULL, | |
| G_TYPE_APPLICATION_FLAGS, G_APPLICATION_DEFAULT_FLAGS, | |
| G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication:resource-base-path: | |
| * | |
| * The base resource path for the application. | |
| * | |
| * Since: 2.28 | |
| */ | |
| g_object_class_install_property (object_class, PROP_RESOURCE_BASE_PATH, | |
| g_param_spec_string ("resource-base-path", NULL, NULL, | |
| NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication:is-registered: | |
| * | |
| * Whether [method@Gio.Application.register] has been called. | |
| * | |
| * Since: 2.28 | |
| */ | |
| g_object_class_install_property (object_class, PROP_IS_REGISTERED, | |
| g_param_spec_boolean ("is-registered", NULL, NULL, | |
| FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication:is-remote: | |
| * | |
| * Whether this application instance is remote. | |
| * | |
| * Since: 2.28 | |
| */ | |
| g_object_class_install_property (object_class, PROP_IS_REMOTE, | |
| g_param_spec_boolean ("is-remote", NULL, NULL, | |
| FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication:inactivity-timeout: | |
| * | |
| * Time (in milliseconds) to stay alive after becoming idle. | |
| * | |
| * Since: 2.28 | |
| */ | |
| g_object_class_install_property (object_class, PROP_INACTIVITY_TIMEOUT, | |
| g_param_spec_uint ("inactivity-timeout", NULL, NULL, | |
| 0, G_MAXUINT, 0, | |
| G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication:action-group: | |
| * | |
| * The group of actions that the application exports. | |
| * | |
| * Since: 2.28 | |
| * Deprecated: 2.32: Use the [iface@Gio.ActionMap] interface instead. | |
| * Never ever mix use of this API with use of `GActionMap` on the | |
| * same @application or things will go very badly wrong. | |
| */ | |
| g_object_class_install_property (object_class, PROP_ACTION_GROUP, | |
| g_param_spec_object ("action-group", NULL, NULL, | |
| G_TYPE_ACTION_GROUP, | |
| G_PARAM_DEPRECATED | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication:is-busy: | |
| * | |
| * Whether the application is currently marked as busy through | |
| * g_application_mark_busy() or g_application_bind_busy_property(). | |
| * | |
| * Since: 2.44 | |
| */ | |
| g_object_class_install_property (object_class, PROP_IS_BUSY, | |
| g_param_spec_boolean ("is-busy", NULL, NULL, | |
| FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); | |
| /** | |
| * GApplication::startup: | |
| * @application: the application | |
| * | |
| * The ::startup signal is emitted on the primary instance immediately | |
| * after registration. See g_application_register(). | |
| */ | |
| g_application_signals[SIGNAL_STARTUP] = | |
| g_signal_new (I_("startup"), G_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST, | |
| G_STRUCT_OFFSET (GApplicationClass, startup), | |
| NULL, NULL, NULL, 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 (I_("shutdown"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, | |
| G_STRUCT_OFFSET (GApplicationClass, shutdown), | |
| NULL, NULL, NULL, G_TYPE_NONE, 0); | |
| /** | |
| * GApplication::activate: | |
| * @application: the application | |
| * | |
| * The ::activate signal is emitted on the primary instance when an | |
| * activation occurs. See g_application_activate(). | |
| */ | |
| g_application_signals[SIGNAL_ACTIVATE] = | |
| g_signal_new (I_("activate"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, | |
| G_STRUCT_OFFSET (GApplicationClass, activate), | |
| NULL, NULL, NULL, G_TYPE_NONE, 0); | |
| /** | |
| * GApplication::open: | |
| * @application: the application | |
| * @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 | |
| * | |
| * The ::open signal is emitted on the primary instance when there are | |
| * files to open. See g_application_open() for more information. | |
| */ | |
| g_application_signals[SIGNAL_OPEN] = | |
| g_signal_new (I_("open"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, | |
| G_STRUCT_OFFSET (GApplicationClass, open), | |
| NULL, NULL, | |
| _g_cclosure_marshal_VOID__POINTER_INT_STRING, | |
| G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_STRING); | |
| g_signal_set_va_marshaller (g_application_signals[SIGNAL_OPEN], | |
| G_TYPE_FROM_CLASS (class), | |
| _g_cclosure_marshal_VOID__POINTER_INT_STRINGv); | |
| /** | |
| * GApplication::command-line: | |
| * @application: the application | |
| * @command_line: a #GApplicationCommandLine representing the | |
| * passed commandline | |
| * | |
| * The ::command-line signal is emitted on the primary instance when | |
| * 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 (I_("command-line"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, | |
| G_STRUCT_OFFSET (GApplicationClass, command_line), | |
| g_signal_accumulator_first_wins, NULL, | |
| _g_cclosure_marshal_INT__OBJECT, | |
| G_TYPE_INT, 1, G_TYPE_APPLICATION_COMMAND_LINE); | |
| g_signal_set_va_marshaller (g_application_signals[SIGNAL_COMMAND_LINE], | |
| G_TYPE_FROM_CLASS (class), | |
| _g_cclosure_marshal_INT__OBJECTv); | |
| /** | |
| * GApplication::handle-local-options: | |
| * @application: the application | |
| * @options: the options dictionary | |
| * | |
| * The ::handle-local-options signal is emitted on the local instance | |
| * after the parsing of the commandline options has occurred. | |
| * | |
| * You can add options to be recognised during commandline option | |
| * parsing using g_application_add_main_option_entries() and | |
| * g_application_add_option_group(). | |
| * | |
| * Signal handlers can inspect @options (along with values pointed to | |
| * from the @arg_data of an installed #GOptionEntrys) in order to | |
| * decide to perform certain actions, including direct local handling | |
| * (which may be useful for options like --version). | |
| * | |
| * In the event that the application is marked | |
| * %G_APPLICATION_HANDLES_COMMAND_LINE the "normal processing" will | |
| * send the @options dictionary to the primary instance where it can be | |
| * read with g_application_command_line_get_options_dict(). The signal | |
| * handler can modify the dictionary before returning, and the | |
| * modified dictionary will be sent. | |
| * | |
| * In the event that %G_APPLICATION_HANDLES_COMMAND_LINE is not set, | |
| * "normal processing" will treat the remaining uncollected command | |
| * line arguments as filenames or URIs. If there are no arguments, | |
| * the application is activated by g_application_activate(). One or | |
| * more arguments results in a call to g_application_open(). | |
| * | |
| * If you want to handle the local commandline arguments for yourself | |
| * by converting them to calls to g_application_open() or | |
| * g_action_group_activate_action() then you must be sure to register | |
| * the application first. You should probably not call | |
| * g_application_activate() for yourself, however: just return -1 and | |
| * allow the default handler to do it for you. This will ensure that | |
| * the `--gapplication-service` switch works properly (i.e. no activation | |
| * in that case). | |
| * | |
| * Note that this signal is emitted from the default implementation of | |
| * local_command_line(). If you override that function and don't | |
| * chain up then this signal will never be emitted. | |
| * | |
| * You can override local_command_line() if you need more powerful | |
| * capabilities than what is provided here, but this should not | |
| * normally be required. | |
| * | |
| * Returns: an exit code. If you have handled your options and want | |
| * to exit the process, return a non-negative option, 0 for success, | |
| * and a positive value for failure. To continue, return -1 to let | |
| * the default option processing continue. | |
| * | |
| * Since: 2.40 | |
| **/ | |
| g_application_signals[SIGNAL_HANDLE_LOCAL_OPTIONS] = | |
| g_signal_new (I_("handle-local-options"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, | |
| G_STRUCT_OFFSET (GApplicationClass, handle_local_options), | |
| g_application_handle_local_options_accumulator, NULL, | |
| _g_cclosure_marshal_INT__BOXED, | |
| G_TYPE_INT, 1, G_TYPE_VARIANT_DICT); | |
| g_signal_set_va_marshaller (g_application_signals[SIGNAL_HANDLE_LOCAL_OPTIONS], | |
| G_TYPE_FROM_CLASS (class), | |
| _g_cclosure_marshal_INT__BOXEDv); | |
| /** | |
| * GApplication::name-lost: | |
| * @application: the application | |
| * | |
| * The ::name-lost signal is emitted only on the registered primary instance | |
| * when a new instance has taken over. This can only happen if the application | |
| * is using the %G_APPLICATION_ALLOW_REPLACEMENT flag. | |
| * | |
| * The default handler for this signal calls g_application_quit(). | |
| * | |
| * Returns: %TRUE if the signal has been handled | |
| * | |
| * Since: 2.60 | |
| */ | |
| g_application_signals[SIGNAL_NAME_LOST] = | |
| g_signal_new (I_("name-lost"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST, | |
| G_STRUCT_OFFSET (GApplicationClass, name_lost), | |
| g_signal_accumulator_true_handled, NULL, | |
| _g_cclosure_marshal_BOOLEAN__VOID, | |
| G_TYPE_BOOLEAN, 0); | |
| g_signal_set_va_marshaller (g_application_signals[SIGNAL_NAME_LOST], | |
| G_TYPE_FROM_CLASS (class), | |
| _g_cclosure_marshal_BOOLEAN__VOIDv); | |
| } | |
| /* Application ID validity {{{1 */ | |
| /** | |
| * g_application_id_is_valid: | |
| * @application_id: a potential application identifier | |
| * | |
| * 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(). | |
| * | |
| * Application identifiers follow the same format as | |
| * [D-Bus well-known bus names](https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus). | |
| * For convenience, the restrictions on application identifiers are | |
| * reproduced here: | |
| * | |
| * - Application identifiers are composed of 1 or more elements separated by a | |
| * period (`.`) character. All elements must contain at least one character. | |
| * | |
| * - Each element must only contain the ASCII characters `[A-Z][a-z][0-9]_-`, | |
| * with `-` discouraged in new application identifiers. Each element 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 exceed 255 characters. | |
| * | |
| * Note that the hyphen (`-`) character is allowed in application identifiers, | |
| * but is problematic or not allowed in various specifications and APIs that | |
| * refer to D-Bus, such as | |
| * [Flatpak application IDs](http://docs.flatpak.org/en/latest/introduction.html#identifiers), | |
| * the | |
| * [`DBusActivatable` interface in the Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus), | |
| * and the convention that an application's "main" interface and object path | |
| * resemble its application identifier and bus name. To avoid situations that | |
| * require special-case handling, it is recommended that new application | |
| * identifiers consistently replace hyphens with underscores. | |
| * | |
| * Like D-Bus interface names, application identifiers should start with the | |
| * reversed DNS domain name of the author of the interface (in lower-case), and | |
| * it is conventional for the rest of the application identifier to consist of | |
| * words run together, with initial capital letters. | |
| * | |
| * As with D-Bus interface names, if the author's DNS domain name contains | |
| * hyphen/minus characters they should be replaced by underscores, and if it | |
| * contains leading digits they should be escaped by prepending an underscore. | |
| * For example, if the owner of 7-zip.org used an application identifier for an | |
| * archiving application, it might be named `org._7_zip.Archiver`. | |
| * | |
| * Returns: %TRUE if @application_id is valid | |
| */ | |
| gboolean | |
| g_application_id_is_valid (const gchar *application_id) | |
| { | |
| return g_dbus_is_name (application_id) && | |
| !g_dbus_is_unique_name (application_id); | |
| } | |
| /* Public Constructor {{{1 */ | |
| /** | |
| * g_application_new: | |
| * @application_id: (nullable): the application id | |
| * @flags: the application flags | |
| * | |
| * Creates a new #GApplication instance. | |
| * | |
| * If non-%NULL, the application id must be valid. See | |
| * g_application_id_is_valid(). | |
| * | |
| * If no application ID is given then some features of #GApplication | |
| * (most notably application uniqueness) will be disabled. | |
| * | |
| * Returns: a new #GApplication instance | |
| **/ | |
| GApplication * | |
| g_application_new (const gchar *application_id, | |
| GApplicationFlags flags) | |
| { | |
| g_return_val_if_fail (application_id == NULL || g_application_id_is_valid (application_id), NULL); | |
| return g_object_new (G_TYPE_APPLICATION, | |
| "application-id", application_id, | |
| "flags", flags, | |
| NULL); | |
| } | |
| /* Simple get/set: application id, flags, inactivity timeout {{{1 */ | |
| /** | |
| * g_application_get_application_id: | |
| * @application: a #GApplication | |
| * | |
| * Gets the unique identifier for @application. | |
| * | |
| * Returns: (nullable): the identifier for @application, owned by @application | |
| * | |
| * Since: 2.28 | |
| **/ | |
| const gchar * | |
| g_application_get_application_id (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), NULL); | |
| return application->priv->id; | |
| } | |
| /** | |
| * g_application_set_application_id: | |
| * @application: a #GApplication | |
| * @application_id: (nullable): the identifier for @application | |
| * | |
| * Sets the unique identifier for @application. | |
| * | |
| * The application id can only be modified if @application has not yet | |
| * been registered. | |
| * | |
| * If non-%NULL, the application id must be valid. See | |
| * g_application_id_is_valid(). | |
| * | |
| * Since: 2.28 | |
| **/ | |
| void | |
| g_application_set_application_id (GApplication *application, | |
| const gchar *application_id) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| if (g_strcmp0 (application->priv->id, application_id) != 0) | |
| { | |
| g_return_if_fail (application_id == NULL || g_application_id_is_valid (application_id)); | |
| g_return_if_fail (!application->priv->is_registered); | |
| g_free (application->priv->id); | |
| application->priv->id = g_strdup (application_id); | |
| g_object_notify (G_OBJECT (application), "application-id"); | |
| } | |
| } | |
| /** | |
| * g_application_get_version: | |
| * @application: a #GApplication | |
| * | |
| * Gets the version of @application. | |
| * | |
| * Returns: (nullable): the version of @application | |
| * | |
| * Since: 2.80 | |
| **/ | |
| const gchar * | |
| g_application_get_version (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), NULL); | |
| return application->priv->version; | |
| } | |
| /** | |
| * g_application_set_version | |
| * @application: a #GApplication | |
| * @version: the version of @application | |
| * | |
| * Sets the version number of @application. This will be used to implement | |
| * a `--version` command line argument | |
| * | |
| * The application version can only be modified if @application has not yet | |
| * been registered. | |
| * | |
| * Since: 2.80 | |
| **/ | |
| void | |
| g_application_set_version (GApplication *application, | |
| const gchar *version) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (version != NULL); | |
| g_return_if_fail (!application->priv->is_registered); | |
| if (g_set_str (&application->priv->version, version)) | |
| g_object_notify (G_OBJECT (application), "version"); | |
| } | |
| /** | |
| * g_application_get_flags: | |
| * @application: a #GApplication | |
| * | |
| * Gets the flags for @application. | |
| * | |
| * See #GApplicationFlags. | |
| * | |
| * Returns: the flags for @application | |
| * | |
| * Since: 2.28 | |
| **/ | |
| GApplicationFlags | |
| g_application_get_flags (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), 0); | |
| return application->priv->flags; | |
| } | |
| /** | |
| * g_application_set_flags: | |
| * @application: a #GApplication | |
| * @flags: the flags for @application | |
| * | |
| * Sets the flags for @application. | |
| * | |
| * The flags can only be modified if @application has not yet been | |
| * registered. | |
| * | |
| * See #GApplicationFlags. | |
| * | |
| * Since: 2.28 | |
| **/ | |
| void | |
| g_application_set_flags (GApplication *application, | |
| GApplicationFlags flags) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| if (application->priv->flags != flags) | |
| { | |
| g_return_if_fail (!application->priv->is_registered); | |
| application->priv->flags = flags; | |
| g_object_notify (G_OBJECT (application), "flags"); | |
| } | |
| } | |
| /** | |
| * g_application_get_resource_base_path: | |
| * @application: a #GApplication | |
| * | |
| * Gets the resource base path of @application. | |
| * | |
| * See g_application_set_resource_base_path() for more information. | |
| * | |
| * Returns: (nullable): the base resource path, if one is set | |
| * | |
| * Since: 2.42 | |
| */ | |
| const gchar * | |
| g_application_get_resource_base_path (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), NULL); | |
| return application->priv->resource_path; | |
| } | |
| /** | |
| * g_application_set_resource_base_path: | |
| * @application: a #GApplication | |
| * @resource_path: (nullable): the resource path to use | |
| * | |
| * Sets (or unsets) the base resource path of @application. | |
| * | |
| * The path is used to automatically load various [application | |
| * resources][gresource] such as menu layouts and action descriptions. | |
| * The various types of resources will be found at fixed names relative | |
| * to the given base path. | |
| * | |
| * By default, the resource base path is determined from the application | |
| * ID by prefixing '/' and replacing each '.' with '/'. This is done at | |
| * the time that the #GApplication object is constructed. Changes to | |
| * the application ID after that point will not have an impact on the | |
| * resource base path. | |
| * | |
| * As an example, if the application has an ID of "org.example.app" then | |
| * the default resource base path will be "/org/example/app". If this | |
| * is a #GtkApplication (and you have not manually changed the path) | |
| * then Gtk will then search for the menus of the application at | |
| * "/org/example/app/gtk/menus.ui". | |
| * | |
| * See #GResource for more information about adding resources to your | |
| * application. | |
| * | |
| * You can disable automatic resource loading functionality by setting | |
| * the path to %NULL. | |
| * | |
| * Changing the resource base path once the application is running is | |
| * not recommended. The point at which the resource path is consulted | |
| * for forming paths for various purposes is unspecified. When writing | |
| * a sub-class of #GApplication you should either set the | |
| * #GApplication:resource-base-path property at construction time, or call | |
| * this function during the instance initialization. Alternatively, you | |
| * can call this function in the #GApplicationClass.startup virtual function, | |
| * before chaining up to the parent implementation. | |
| * | |
| * Since: 2.42 | |
| */ | |
| void | |
| g_application_set_resource_base_path (GApplication *application, | |
| const gchar *resource_path) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (resource_path == NULL || g_str_has_prefix (resource_path, "/")); | |
| if (g_strcmp0 (application->priv->resource_path, resource_path) != 0) | |
| { | |
| g_free (application->priv->resource_path); | |
| application->priv->resource_path = g_strdup (resource_path); | |
| g_object_notify (G_OBJECT (application), "resource-base-path"); | |
| } | |
| } | |
| /** | |
| * g_application_get_inactivity_timeout: | |
| * @application: a #GApplication | |
| * | |
| * Gets the current inactivity timeout for the application. | |
| * | |
| * This is the amount of time (in milliseconds) after the last call to | |
| * g_application_release() before the application stops running. | |
| * | |
| * Returns: the timeout, in milliseconds | |
| * | |
| * Since: 2.28 | |
| **/ | |
| guint | |
| g_application_get_inactivity_timeout (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), 0); | |
| return application->priv->inactivity_timeout; | |
| } | |
| /** | |
| * g_application_set_inactivity_timeout: | |
| * @application: a #GApplication | |
| * @inactivity_timeout: the timeout, in milliseconds | |
| * | |
| * Sets the current inactivity timeout for the application. | |
| * | |
| * This is the amount of time (in milliseconds) after the last call to | |
| * g_application_release() before the application stops running. | |
| * | |
| * This call has no side effects of its own. The value set here is only | |
| * used for next time g_application_release() drops the use count to | |
| * zero. Any timeouts currently in progress are not impacted. | |
| * | |
| * Since: 2.28 | |
| **/ | |
| void | |
| g_application_set_inactivity_timeout (GApplication *application, | |
| guint inactivity_timeout) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| if (application->priv->inactivity_timeout != inactivity_timeout) | |
| { | |
| application->priv->inactivity_timeout = inactivity_timeout; | |
| g_object_notify (G_OBJECT (application), "inactivity-timeout"); | |
| } | |
| } | |
| /* Read-only property getters (is registered, is remote, dbus stuff) {{{1 */ | |
| /** | |
| * g_application_get_is_registered: | |
| * @application: a #GApplication | |
| * | |
| * 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 | |
| g_application_get_is_registered (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); | |
| return application->priv->is_registered; | |
| } | |
| /** | |
| * g_application_get_is_remote: | |
| * @application: a #GApplication | |
| * | |
| * Checks if @application is remote. | |
| * | |
| * If @application is remote then it means that another instance of | |
| * application already exists (the 'primary' instance). Calls to | |
| * perform actions on @application will result in the actions being | |
| * performed by the primary instance. | |
| * | |
| * 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 | |
| g_application_get_is_remote (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); | |
| g_return_val_if_fail (application->priv->is_registered, FALSE); | |
| return application->priv->is_remote; | |
| } | |
| /** | |
| * g_application_get_dbus_connection: | |
| * @application: a #GApplication | |
| * | |
| * Gets the #GDBusConnection being used by the application, or %NULL. | |
| * | |
| * If #GApplication is using its D-Bus backend then this function will | |
| * return the #GDBusConnection being used for uniqueness and | |
| * communication with the desktop environment and other instances of the | |
| * application. | |
| * | |
| * If #GApplication is not using D-Bus then this function will return | |
| * %NULL. This includes the situation where the D-Bus backend would | |
| * normally be in use but we were unable to connect to the bus. | |
| * | |
| * This function must not be called before the application has been | |
| * registered. See g_application_get_is_registered(). | |
| * | |
| * Returns: (nullable) (transfer none): a #GDBusConnection, or %NULL | |
| * | |
| * Since: 2.34 | |
| **/ | |
| GDBusConnection * | |
| g_application_get_dbus_connection (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); | |
| g_return_val_if_fail (application->priv->is_registered, FALSE); | |
| return g_application_impl_get_dbus_connection (application->priv->impl); | |
| } | |
| /** | |
| * g_application_get_dbus_object_path: | |
| * @application: a #GApplication | |
| * | |
| * Gets the D-Bus object path being used by the application, or %NULL. | |
| * | |
| * If #GApplication is using its D-Bus backend then this function will | |
| * return the D-Bus object path that #GApplication is using. If the | |
| * application is the primary instance then there is an object published | |
| * at this path. If the application is not the primary instance then | |
| * the result of this function is undefined. | |
| * | |
| * If #GApplication is not using D-Bus then this function will return | |
| * %NULL. This includes the situation where the D-Bus backend would | |
| * normally be in use but we were unable to connect to the bus. | |
| * | |
| * This function must not be called before the application has been | |
| * registered. See g_application_get_is_registered(). | |
| * | |
| * Returns: (nullable): the object path, or %NULL | |
| * | |
| * Since: 2.34 | |
| **/ | |
| const gchar * | |
| g_application_get_dbus_object_path (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); | |
| g_return_val_if_fail (application->priv->is_registered, FALSE); | |
| return g_application_impl_get_dbus_object_path (application->priv->impl); | |
| } | |
| /* Register {{{1 */ | |
| /** | |
| * g_application_register: | |
| * @application: a #GApplication | |
| * @cancellable: (nullable): a #GCancellable, or %NULL | |
| * @error: a pointer to a NULL #GError, or %NULL | |
| * | |
| * 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. This is implemented by attempting to acquire the | |
| * application identifier as a unique bus name on the session bus using | |
| * GDBus. | |
| * | |
| * If there is no application ID or if %G_APPLICATION_NON_UNIQUE was | |
| * given, then this process will always become the primary instance. | |
| * | |
| * 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 #GApplication::startup signal is emitted if registration succeeds | |
| * and @application is the primary instance (including the non-unique | |
| * case). | |
| * | |
| * In the event of an error (such as @cancellable being cancelled, or a | |
| * failure to connect to the session bus), %FALSE is returned and @error | |
| * is set appropriately. | |
| * | |
| * Note: the return value of this function is not an indicator that this | |
| * 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 | |
| g_application_register (GApplication *application, | |
| GCancellable *cancellable, | |
| GError **error) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); | |
| if (!application->priv->is_registered) | |
| { | |
| if (application->priv->id == NULL) | |
| application->priv->flags |= G_APPLICATION_NON_UNIQUE; | |
| application->priv->impl = | |
| g_application_impl_register (application, application->priv->id, | |
| application->priv->flags, | |
| application->priv->actions, | |
| &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; | |
| g_object_notify (G_OBJECT (application), "is-registered"); | |
| 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; | |
| } | |
| /* Hold/release {{{1 */ | |
| /** | |
| * g_application_hold: | |
| * @application: a #GApplication | |
| * | |
| * 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 | |
| * when a toplevel window is on the screen. | |
| * | |
| * To cancel the hold, call g_application_release(). | |
| **/ | |
| void | |
| g_application_hold (GApplication *application) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| if (application->priv->inactivity_timeout_id) | |
| { | |
| g_source_remove (application->priv->inactivity_timeout_id); | |
| application->priv->inactivity_timeout_id = 0; | |
| } | |
| application->priv->use_count++; | |
| } | |
| static gboolean | |
| inactivity_timeout_expired (gpointer data) | |
| { | |
| GApplication *application = G_APPLICATION (data); | |
| application->priv->inactivity_timeout_id = 0; | |
| return G_SOURCE_REMOVE; | |
| } | |
| /** | |
| * g_application_release: | |
| * @application: a #GApplication | |
| * | |
| * Decrease the use count of @application. | |
| * | |
| * When the use count reaches zero, the application will stop running. | |
| * | |
| * Never call this function except to cancel the effect of a previous | |
| * call to g_application_hold(). | |
| **/ | |
| void | |
| g_application_release (GApplication *application) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (application->priv->use_count > 0); | |
| application->priv->use_count--; | |
| 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 */ | |
| /** | |
| * g_application_activate: | |
| * @application: a #GApplication | |
| * | |
| * Activates the application. | |
| * | |
| * In essence, this results in the #GApplication::activate signal being | |
| * emitted in the primary instance. | |
| * | |
| * The application must be registered before calling this function. | |
| * | |
| * Since: 2.28 | |
| **/ | |
| void | |
| g_application_activate (GApplication *application) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (application->priv->is_registered); | |
| if (application->priv->is_remote) | |
| g_application_impl_activate (application->priv->impl, | |
| get_platform_data (application, NULL)); | |
| else | |
| g_signal_emit (application, g_application_signals[SIGNAL_ACTIVATE], 0); | |
| } | |
| /** | |
| * g_application_open: | |
| * @application: a #GApplication | |
| * @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 #GApplication::open signal being emitted | |
| * in the primary instance. | |
| * | |
| * @n_files must be greater than zero. | |
| * | |
| * @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. | |
| * | |
| * Since: 2.28 | |
| **/ | |
| void | |
| g_application_open (GApplication *application, | |
| GFile **files, | |
| gint n_files, | |
| const gchar *hint) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (application->priv->flags & | |
| G_APPLICATION_HANDLES_OPEN); | |
| g_return_if_fail (application->priv->is_registered); | |
| if (application->priv->is_remote) | |
| g_application_impl_open (application->priv->impl, | |
| files, n_files, hint, | |
| get_platform_data (application, NULL)); | |
| else | |
| g_signal_emit (application, g_application_signals[SIGNAL_OPEN], | |
| 0, files, n_files, hint); | |
| } | |
| /* Run {{{1 */ | |
| /** | |
| * g_application_run: | |
| * @application: a #GApplication | |
| * @argc: the argc from main() (or 0 if @argv is %NULL) | |
| * @argv: (array length=argc) (element-type filename) (nullable): | |
| * 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(). 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. Note that on Windows, @argc and @argv are ignored, and | |
| * g_win32_get_command_line() is called internally (for proper support | |
| * of Unicode commandline arguments). | |
| * | |
| * #GApplication will attempt to parse the commandline arguments. You | |
| * can add commandline flags to the list of recognised options by way of | |
| * g_application_add_main_option_entries(). After this, the | |
| * #GApplication::handle-local-options signal is emitted, from which the | |
| * application can inspect the values of its #GOptionEntrys. | |
| * | |
| * #GApplication::handle-local-options is a good place to handle options | |
| * such as `--version`, where an immediate reply from the local process is | |
| * desired (instead of communicating with an already-running instance). | |
| * A #GApplication::handle-local-options handler can stop further processing | |
| * by returning a non-negative value, which then becomes the exit status of | |
| * the process. | |
| * | |
| * What happens next depends on the flags: if | |
| * %G_APPLICATION_HANDLES_COMMAND_LINE was specified then the remaining | |
| * commandline arguments are sent to the primary instance, where a | |
| * #GApplication::command-line signal is emitted. Otherwise, the | |
| * remaining commandline arguments are assumed to be a list of files. | |
| * If there are no files listed, the application is activated via the | |
| * #GApplication::activate signal. If there are one or more files, and | |
| * %G_APPLICATION_HANDLES_OPEN was specified then the files are opened | |
| * via the #GApplication::open signal. | |
| * | |
| * 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(). In this case, you most likely want | |
| * to return %TRUE from your local_command_line() implementation to | |
| * suppress the default handling. See | |
| * [gapplication-example-cmdline2.c][https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-cmdline2.c] | |
| * 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 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 service will | |
| * run for as much as 10 seconds with a use count of zero while waiting | |
| * for the message that caused the activation to arrive. After that, | |
| * if the use count falls to zero the application will exit immediately, | |
| * except in the case that g_application_set_inactivity_timeout() is in | |
| * use. | |
| * | |
| * This function sets the prgname (g_set_prgname()), if not already set, | |
| * to the basename of argv[0]. | |
| * | |
| * Much like g_main_loop_run(), this function will acquire the main context | |
| * for the duration that the application is running. | |
| * | |
| * Since 2.40, applications that are not explicitly flagged as services | |
| * or launchers (ie: neither %G_APPLICATION_IS_SERVICE or | |
| * %G_APPLICATION_IS_LAUNCHER are given as flags) will check (from the | |
| * default handler for local_command_line) if "--gapplication-service" | |
| * was given in the command line. If this flag is present then normal | |
| * commandline processing is interrupted and the | |
| * %G_APPLICATION_IS_SERVICE flag is set. This provides a "compromise" | |
| * solution whereby running an application directly from the commandline | |
| * will invoke it in the normal way (which can be useful for debugging) | |
| * while still allowing applications to be D-Bus activated in service | |
| * mode. The D-Bus service file should invoke the executable with | |
| * "--gapplication-service" as the sole commandline argument. This | |
| * approach is suitable for use by most graphical applications but | |
| * should not be used from applications like editors that need precise | |
| * control over when processes invoked via the commandline will exit and | |
| * what their exit status will be. | |
| * | |
| * Returns: the exit status | |
| * | |
| * Since: 2.28 | |
| **/ | |
| int | |
| g_application_run (GApplication *application, | |
| int argc, | |
| char **argv) | |
| { | |
| gchar **arguments; | |
| int status; | |
| GMainContext *context; | |
| gboolean acquired_context; | |
| g_return_val_if_fail (G_IS_APPLICATION (application), 1); | |
| g_return_val_if_fail (argc == 0 || argv != NULL, 1); | |
| g_return_val_if_fail (!application->priv->must_quit_now, 1); | |
| #ifdef G_OS_WIN32 | |
| { | |
| gint new_argc = 0; | |
| arguments = g_win32_get_command_line (); | |
| /* | |
| * CommandLineToArgvW(), which is called by g_win32_get_command_line(), | |
| * pulls in the whole command line that is used to call the program. This is | |
| * fine in cases where the program is a .exe program, but in the cases where the | |
| * program is a called via a script, such as PyGObject's gtk-demo.py, which is normally | |
| * called using 'python gtk-demo.py' on Windows, the program name (argv[0]) | |
| * returned by g_win32_get_command_line() will not be the argv[0] that ->local_command_line() | |
| * would expect, causing the program to fail with "This application can not open files." | |
| */ | |
| new_argc = g_strv_length (arguments); | |
| if (new_argc > argc) | |
| { | |
| gint i; | |
| for (i = 0; i < new_argc - argc; i++) | |
| g_free (arguments[i]); | |
| memmove (&arguments[0], | |
| &arguments[new_argc - argc], | |
| sizeof (arguments[0]) * (argc + 1)); | |
| } | |
| } | |
| #elif defined(__APPLE__) | |
| { | |
| gint i, j; | |
| /* | |
| * OSX adds an unexpected parameter on the format -psn_X_XXXXXX | |
| * when opening the application using Launch Services. In order | |
| * to avoid that GOption fails to parse this parameter we just | |
| * skip it if it was provided. | |
| * See: https://gitlab.gnome.org/GNOME/glib/issues/1784 | |
| */ | |
| arguments = g_new (gchar *, argc + 1); | |
| for (i = 0, j = 0; i < argc; i++) | |
| { | |
| if (!g_str_has_prefix (argv[i], "-psn_")) | |
| { | |
| arguments[j] = g_strdup (argv[i]); | |
| j++; | |
| } | |
| } | |
| arguments[j] = NULL; | |
| } | |
| #else | |
| { | |
| gint i; | |
| arguments = g_new (gchar *, argc + 1); | |
| for (i = 0; i < argc; i++) | |
| arguments[i] = g_strdup (argv[i]); | |
| arguments[i] = NULL; | |
| } | |
| #endif | |
| if (g_get_prgname () == NULL && argc > 0) | |
| { | |
| gchar *prgname; | |
| prgname = g_path_get_basename (argv[0]); | |
| GLIB_PRIVATE_CALL (g_set_prgname_once) (prgname); | |
| g_free (prgname); | |
| } | |
| context = g_main_context_default (); | |
| acquired_context = g_main_context_acquire (context); | |
| if (!acquired_context) | |
| { | |
| g_critical ("g_application_run() cannot acquire the default main context because it is already acquired by another thread!"); | |
| g_strfreev (arguments); | |
| return 1; | |
| } | |
| if (!G_APPLICATION_GET_CLASS (application) | |
| ->local_command_line (application, &arguments, &status)) | |
| { | |
| GError *error = NULL; | |
| if (!g_application_register (application, NULL, &error)) | |
| { | |
| g_printerr ("Failed to register: %s\n", error->message); | |
| g_error_free (error); | |
| return 1; | |
| } | |
| g_application_call_command_line (application, (const gchar **) arguments, NULL, &status); | |
| } | |
| g_strfreev (arguments); | |
| if (application->priv->flags & G_APPLICATION_IS_SERVICE && | |
| application->priv->is_registered && | |
| !application->priv->use_count && | |
| !application->priv->inactivity_timeout_id) | |
| { | |
| application->priv->inactivity_timeout_id = | |
| g_timeout_add (10000, inactivity_timeout_expired, application); | |
| } | |
| while (application->priv->use_count || application->priv->inactivity_timeout_id) | |
| { | |
| if (application->priv->must_quit_now) | |
| break; | |
| g_main_context_iteration (context, TRUE); | |
| status = 0; | |
| } | |
| if (application->priv->is_registered && !application->priv->is_remote) | |
| { | |
| g_signal_emit (application, g_application_signals[SIGNAL_SHUTDOWN], 0); | |
| 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)); | |
| } | |
| if (application->priv->impl) | |
| { | |
| if (application->priv->is_registered) | |
| { | |
| application->priv->is_registered = FALSE; | |
| g_object_notify (G_OBJECT (application), "is-registered"); | |
| } | |
| g_application_impl_flush (application->priv->impl); | |
| g_application_impl_destroy (application->priv->impl); | |
| application->priv->impl = NULL; | |
| } | |
| g_settings_sync (); | |
| if (!application->priv->must_quit_now) | |
| while (g_main_context_iteration (context, FALSE)) | |
| ; | |
| g_main_context_release (context); | |
| return status; | |
| } | |
| static gchar ** | |
| g_application_list_actions (GActionGroup *action_group) | |
| { | |
| GApplication *application = G_APPLICATION (action_group); | |
| g_return_val_if_fail (application->priv->is_registered, NULL); | |
| if (application->priv->remote_actions != NULL) | |
| return g_action_group_list_actions (G_ACTION_GROUP (application->priv->remote_actions)); | |
| else if (application->priv->actions != NULL) | |
| return g_action_group_list_actions (application->priv->actions); | |
| else | |
| /* empty string array */ | |
| return g_new0 (gchar *, 1); | |
| } | |
| static gboolean | |
| 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 (group); | |
| g_return_val_if_fail (application->priv->is_registered, FALSE); | |
| if (application->priv->remote_actions != NULL) | |
| return g_action_group_query_action (G_ACTION_GROUP (application->priv->remote_actions), | |
| action_name, | |
| enabled, | |
| parameter_type, | |
| state_type, | |
| state_hint, | |
| state); | |
| 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 FALSE; | |
| } | |
| static void | |
| g_application_change_action_state (GActionGroup *action_group, | |
| const gchar *action_name, | |
| GVariant *value) | |
| { | |
| 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->remote_actions) | |
| g_remote_action_group_change_action_state_full (application->priv->remote_actions, | |
| action_name, value, get_platform_data (application, NULL)); | |
| else | |
| g_action_group_change_action_state (application->priv->actions, action_name, value); | |
| } | |
| static void | |
| g_application_activate_action (GActionGroup *action_group, | |
| const gchar *action_name, | |
| GVariant *parameter) | |
| { | |
| 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->remote_actions) | |
| g_remote_action_group_activate_action_full (application->priv->remote_actions, | |
| action_name, parameter, get_platform_data (application, NULL)); | |
| else | |
| g_action_group_activate_action (application->priv->actions, action_name, parameter); | |
| } | |
| static GAction * | |
| g_application_lookup_action (GActionMap *action_map, | |
| const gchar *action_name) | |
| { | |
| GApplication *application = G_APPLICATION (action_map); | |
| g_return_val_if_fail (G_IS_ACTION_MAP (application->priv->actions), NULL); | |
| return g_action_map_lookup_action (G_ACTION_MAP (application->priv->actions), action_name); | |
| } | |
| static void | |
| g_application_add_action (GActionMap *action_map, | |
| GAction *action) | |
| { | |
| GApplication *application = G_APPLICATION (action_map); | |
| g_return_if_fail (G_IS_ACTION_MAP (application->priv->actions)); | |
| g_action_map_add_action (G_ACTION_MAP (application->priv->actions), action); | |
| } | |
| static void | |
| g_application_remove_action (GActionMap *action_map, | |
| const gchar *action_name) | |
| { | |
| GApplication *application = G_APPLICATION (action_map); | |
| g_return_if_fail (G_IS_ACTION_MAP (application->priv->actions)); | |
| g_action_map_remove_action (G_ACTION_MAP (application->priv->actions), action_name); | |
| } | |
| static void | |
| g_application_action_group_iface_init (GActionGroupInterface *iface) | |
| { | |
| iface->list_actions = g_application_list_actions; | |
| iface->query_action = g_application_query_action; | |
| iface->change_action_state = g_application_change_action_state; | |
| iface->activate_action = g_application_activate_action; | |
| } | |
| static void | |
| g_application_action_map_iface_init (GActionMapInterface *iface) | |
| { | |
| iface->lookup_action = g_application_lookup_action; | |
| iface->add_action = g_application_add_action; | |
| iface->remove_action = g_application_remove_action; | |
| } | |
| /* Default Application {{{1 */ | |
| static GApplication *default_app; | |
| /** | |
| * g_application_get_default: | |
| * | |
| * 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. | |
| * | |
| * Returns: (nullable) (transfer none): the default application for this process, or %NULL | |
| * | |
| * Since: 2.32 | |
| **/ | |
| GApplication * | |
| g_application_get_default (void) | |
| { | |
| return default_app; | |
| } | |
| /** | |
| * g_application_set_default: | |
| * @application: (nullable): 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; | |
| } | |
| /** | |
| * g_application_quit: | |
| * @application: a #GApplication | |
| * | |
| * Immediately quits the application. | |
| * | |
| * Upon return to the mainloop, g_application_run() will return, | |
| * calling only the 'shutdown' function before doing so. | |
| * | |
| * The hold count is ignored. | |
| * Take care if your code has called g_application_hold() on the application and | |
| * is therefore still expecting it to exist. | |
| * (Note that you may have called g_application_hold() indirectly, for example | |
| * through gtk_application_add_window().) | |
| * | |
| * The result of calling g_application_run() again after it returns is | |
| * unspecified. | |
| * | |
| * Since: 2.32 | |
| **/ | |
| void | |
| g_application_quit (GApplication *application) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| application->priv->must_quit_now = TRUE; | |
| } | |
| /** | |
| * g_application_mark_busy: | |
| * @application: a #GApplication | |
| * | |
| * Increases the busy count of @application. | |
| * | |
| * Use this function to indicate that the application is busy, for instance | |
| * while a long running operation is pending. | |
| * | |
| * The busy state will be exposed to other processes, so a session shell will | |
| * use that information to indicate the state to the user (e.g. with a | |
| * spinner). | |
| * | |
| * To cancel the busy indication, use g_application_unmark_busy(). | |
| * | |
| * The application must be registered before calling this function. | |
| * | |
| * Since: 2.38 | |
| **/ | |
| void | |
| g_application_mark_busy (GApplication *application) | |
| { | |
| gboolean was_busy; | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (application->priv->is_registered); | |
| was_busy = (application->priv->busy_count > 0); | |
| application->priv->busy_count++; | |
| if (!was_busy) | |
| { | |
| g_application_impl_set_busy_state (application->priv->impl, TRUE); | |
| g_object_notify (G_OBJECT (application), "is-busy"); | |
| } | |
| } | |
| /** | |
| * g_application_unmark_busy: | |
| * @application: a #GApplication | |
| * | |
| * Decreases the busy count of @application. | |
| * | |
| * When the busy count reaches zero, the new state will be propagated | |
| * to other processes. | |
| * | |
| * This function must only be called to cancel the effect of a previous | |
| * call to g_application_mark_busy(). | |
| * | |
| * Since: 2.38 | |
| **/ | |
| void | |
| g_application_unmark_busy (GApplication *application) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (application->priv->busy_count > 0); | |
| application->priv->busy_count--; | |
| if (application->priv->busy_count == 0) | |
| { | |
| g_application_impl_set_busy_state (application->priv->impl, FALSE); | |
| g_object_notify (G_OBJECT (application), "is-busy"); | |
| } | |
| } | |
| /** | |
| * g_application_get_is_busy: | |
| * @application: a #GApplication | |
| * | |
| * Gets the application's current busy state, as set through | |
| * g_application_mark_busy() or g_application_bind_busy_property(). | |
| * | |
| * Returns: %TRUE if @application is currently marked as busy | |
| * | |
| * Since: 2.44 | |
| */ | |
| gboolean | |
| g_application_get_is_busy (GApplication *application) | |
| { | |
| g_return_val_if_fail (G_IS_APPLICATION (application), FALSE); | |
| return application->priv->busy_count > 0; | |
| } | |
| /* Notifications {{{1 */ | |
| /** | |
| * g_application_send_notification: | |
| * @application: a #GApplication | |
| * @id: (nullable): id of the notification, or %NULL | |
| * @notification: the #GNotification to send | |
| * | |
| * Sends a notification on behalf of @application to the desktop shell. | |
| * There is no guarantee that the notification is displayed immediately, | |
| * or even at all. | |
| * | |
| * Notifications may persist after the application exits. It will be | |
| * D-Bus-activated when the notification or one of its actions is | |
| * activated. | |
| * | |
| * Modifying @notification after this call has no effect. However, the | |
| * object can be reused for a later call to this function. | |
| * | |
| * @id may be any string that uniquely identifies the event for the | |
| * application. It does not need to be in any special format. For | |
| * example, "new-message" might be appropriate for a notification about | |
| * new messages. | |
| * | |
| * If a previous notification was sent with the same @id, it will be | |
| * replaced with @notification and shown again as if it was a new | |
| * notification. This works even for notifications sent from a previous | |
| * execution of the application, as long as @id is the same string. | |
| * | |
| * @id may be `NULL`, but it is impossible to replace or withdraw | |
| * notifications without an id. | |
| * | |
| * If @notification is no longer relevant, it can be withdrawn with | |
| * [method@Gio.Application.withdraw_notification]. | |
| * | |
| * It is an error to call this function if @application has no | |
| * application ID. | |
| * | |
| * Since: 2.40 | |
| */ | |
| void | |
| g_application_send_notification (GApplication *application, | |
| const gchar *id, | |
| GNotification *notification) | |
| { | |
| gchar *generated_id = NULL; | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (G_IS_NOTIFICATION (notification)); | |
| g_return_if_fail (g_application_get_is_registered (application)); | |
| g_return_if_fail (!g_application_get_is_remote (application)); | |
| g_return_if_fail (g_application_get_application_id (application) != NULL); | |
| if (application->priv->notifications == NULL) | |
| application->priv->notifications = g_notification_backend_new_default (application); | |
| if (id == NULL) | |
| { | |
| generated_id = g_dbus_generate_guid (); | |
| id = generated_id; | |
| } | |
| g_notification_backend_send_notification (application->priv->notifications, id, notification); | |
| g_free (generated_id); | |
| } | |
| /** | |
| * g_application_withdraw_notification: | |
| * @application: a #GApplication | |
| * @id: id of a previously sent notification | |
| * | |
| * Withdraws a notification that was sent with | |
| * g_application_send_notification(). | |
| * | |
| * This call does nothing if a notification with @id doesn't exist or | |
| * the notification was never sent. | |
| * | |
| * This function works even for notifications sent in previous | |
| * executions of this application, as long @id is the same as it was for | |
| * the sent notification. | |
| * | |
| * Note that notifications are dismissed when the user clicks on one | |
| * of the buttons in a notification or triggers its default action, so | |
| * there is no need to explicitly withdraw the notification in that case. | |
| * | |
| * Since: 2.40 | |
| */ | |
| void | |
| g_application_withdraw_notification (GApplication *application, | |
| const gchar *id) | |
| { | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (id != NULL); | |
| if (application->priv->notifications == NULL) | |
| application->priv->notifications = g_notification_backend_new_default (application); | |
| g_notification_backend_withdraw_notification (application->priv->notifications, id); | |
| } | |
| /* Busy binding {{{1 */ | |
| typedef struct | |
| { | |
| GApplication *app; | |
| gboolean is_busy; | |
| } GApplicationBusyBinding; | |
| static void | |
| g_application_busy_binding_destroy (gpointer data, | |
| GClosure *closure) | |
| { | |
| GApplicationBusyBinding *binding = data; | |
| if (binding->is_busy) | |
| g_application_unmark_busy (binding->app); | |
| g_object_unref (binding->app); | |
| g_slice_free (GApplicationBusyBinding, binding); | |
| } | |
| static void | |
| g_application_notify_busy_binding (GObject *object, | |
| GParamSpec *pspec, | |
| gpointer user_data) | |
| { | |
| GApplicationBusyBinding *binding = user_data; | |
| gboolean is_busy; | |
| g_object_get (object, pspec->name, &is_busy, NULL); | |
| if (is_busy && !binding->is_busy) | |
| g_application_mark_busy (binding->app); | |
| else if (!is_busy && binding->is_busy) | |
| g_application_unmark_busy (binding->app); | |
| binding->is_busy = is_busy; | |
| } | |
| /** | |
| * g_application_bind_busy_property: | |
| * @application: a #GApplication | |
| * @object: (type GObject.Object): a #GObject | |
| * @property: the name of a boolean property of @object | |
| * | |
| * Marks @application as busy (see g_application_mark_busy()) while | |
| * @property on @object is %TRUE. | |
| * | |
| * The binding holds a reference to @application while it is active, but | |
| * not to @object. Instead, the binding is destroyed when @object is | |
| * finalized. | |
| * | |
| * Since: 2.44 | |
| */ | |
| void | |
| g_application_bind_busy_property (GApplication *application, | |
| gpointer object, | |
| const gchar *property) | |
| { | |
| guint notify_id; | |
| GQuark property_quark; | |
| GParamSpec *pspec; | |
| GApplicationBusyBinding *binding; | |
| GClosure *closure; | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (G_IS_OBJECT (object)); | |
| g_return_if_fail (property != NULL); | |
| notify_id = g_signal_lookup ("notify", G_TYPE_OBJECT); | |
| property_quark = g_quark_from_string (property); | |
| pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property); | |
| g_return_if_fail (pspec != NULL && pspec->value_type == G_TYPE_BOOLEAN); | |
| if (g_signal_handler_find (object, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC, | |
| notify_id, property_quark, NULL, g_application_notify_busy_binding, NULL) > 0) | |
| { | |
| g_critical ("%s: '%s' is already bound to the busy state of the application", G_STRFUNC, property); | |
| return; | |
| } | |
| binding = g_slice_new (GApplicationBusyBinding); | |
| binding->app = g_object_ref (application); | |
| binding->is_busy = FALSE; | |
| closure = g_cclosure_new (G_CALLBACK (g_application_notify_busy_binding), binding, | |
| g_application_busy_binding_destroy); | |
| g_signal_connect_closure_by_id (object, notify_id, property_quark, closure, FALSE); | |
| /* fetch the initial value */ | |
| g_application_notify_busy_binding (object, pspec, binding); | |
| } | |
| /** | |
| * g_application_unbind_busy_property: | |
| * @application: a #GApplication | |
| * @object: (type GObject.Object): a #GObject | |
| * @property: the name of a boolean property of @object | |
| * | |
| * Destroys a binding between @property and the busy state of | |
| * @application that was previously created with | |
| * g_application_bind_busy_property(). | |
| * | |
| * Since: 2.44 | |
| */ | |
| void | |
| g_application_unbind_busy_property (GApplication *application, | |
| gpointer object, | |
| const gchar *property) | |
| { | |
| guint notify_id; | |
| GQuark property_quark; | |
| gulong handler_id; | |
| g_return_if_fail (G_IS_APPLICATION (application)); | |
| g_return_if_fail (G_IS_OBJECT (object)); | |
| g_return_if_fail (property != NULL); | |
| notify_id = g_signal_lookup ("notify", G_TYPE_OBJECT); | |
| property_quark = g_quark_from_string (property); | |
| handler_id = g_signal_handler_find (object, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC, | |
| notify_id, property_quark, NULL, g_application_notify_busy_binding, NULL); | |
| if (handler_id == 0) | |
| { | |
| g_critical ("%s: '%s' is not bound to the busy state of the application", G_STRFUNC, property); | |
| return; | |
| } | |
| g_signal_handler_disconnect (object, handler_id); | |
| } | |
| /* Epilogue {{{1 */ | |
| /* vim:set foldmethod=marker: */ |