apps test: add new "monitor" subcommand
[platform/upstream/glib.git] / gio / gapplication.c
index 1309ef0..9546ae8 100644 (file)
  * this class outside of a higher level framework.
  *
  * GApplication provides convenient life cycle management by maintaining
- * a <firstterm>use count</firstterm> for the primary application instance.
- * The use count can be changed using g_application_hold() and
- * g_application_release(). If it drops to zero, the application exits.
- * 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.
+ * a "use count" for the primary application instance. The use count can
+ * be changed using g_application_hold() and g_application_release(). If
+ * it drops to zero, the application exits. 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
+ * 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
+ * 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 <firstterm>primary instance</firstterm>; for non-unique
- * applications this is the always the current instance.
- * On Linux, the D-Bus session bus is used for communication.
+ * running program. The already running instance of the program is
+ * called the "primary instance"; for non-unique applications this is
+ * the 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
  * The #GApplication::startup signal lets you handle the application
  * initialization for all of these in a single place.
  *
- * Regardless of which of these entry points is used to start the application,
- * GApplication passes some <firstterm id="platform-data">platform
- * data</firstterm> from the launching instance to the primary instance,
- * in the form of a #GVariant dictionary mapping strings to variants.
- * To use platform data, override the @before_emit or @after_emit virtual
- * functions in your #GApplication subclass. When dealing with
- * #GApplicationCommandLine objects, the platform data is directly
- * available via g_application_command_line_get_cwd(),
+ * Regardless of which of these entry points is used to start the
+ * application, GApplication passes some "platform data from the
+ * launching instance to the primary instance, in the form of a
+ * #GVariant dictionary mapping strings to variants. To use platform
+ * data, override the @before_emit or @after_emit virtual functions
+ * in your #GApplication subclass. When dealing with
+ * #GApplicationCommandLine objects, the platform data is
+ * directly available via g_application_command_line_get_cwd(),
  * g_application_command_line_get_environ() and
  * g_application_command_line_get_platform_data().
  *
  * vfunc, to parse them in either the primary instance or the local instance,
  * respectively.
  *
- * <example id="gapplication-example-open"><title>Opening files with a GApplication</title>
- * <programlisting>
- * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-open.c">
- *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
- * </xi:include>
- * </programlisting>
- * </example>
- *
- * <example id="gapplication-example-actions"><title>A GApplication with actions</title>
- * <programlisting>
- * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-actions.c">
- *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
- * </xi:include>
- * </programlisting>
- * </example>
- *
- * <example id="gapplication-example-dbushooks"><title>Using extra D-Bus hooks with a GApplication</title>
- * <programlisting>
- * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-dbushooks.c">
- *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
- * </xi:include>
- * </programlisting>
- * </example>
+ * For an example of opening files with a GApplication, see
+ * [gapplication-example-open.c](https://git.gnome.org/browse/glib/tree/gio/tests/gapplication-example-open.c).
+ *
+ * For an example of using actions with GApplication, see
+ * [gapplication-example-actions.c](https://git.gnome.org/browse/glib/tree/gio/tests/gapplication-example-actions.c).
+ *
+ * For an example of using extra D-Bus hooks with GApplication, see
+ * [gapplication-example-dbushooks.c](https://git.gnome.org/browse/glib/tree/gio/tests/gapplication-example-dbushooks.c).
  */
 
 /**
@@ -228,6 +212,7 @@ struct _GApplicationPrivate
 {
   GApplicationFlags  flags;
   gchar             *id;
+  gchar             *resource_path;
 
   GActionGroup      *actions;
   GMenuModel        *app_menu;
@@ -254,6 +239,9 @@ struct _GApplicationPrivate
   GSList             *option_groups;
   GHashTable         *packed_options;
   gboolean            options_parsed;
+
+  /* Allocated option strings, from g_application_add_main_option() */
+  GSList             *option_strings;
 };
 
 enum
@@ -261,6 +249,7 @@ enum
   PROP_NONE,
   PROP_APPLICATION_ID,
   PROP_FLAGS,
+  PROP_RESOURCE_BASE_PATH,
   PROP_IS_REGISTERED,
   PROP_IS_REMOTE,
   PROP_INACTIVITY_TIMEOUT,
@@ -605,7 +594,8 @@ add_packed_option (GApplication *application,
 /**
  * g_application_add_main_option_entries:
  * @application: a #GApplication
- * @entries: a %NULL-terminated list of #GOptionEntrys
+ * @entries: (array zero-terminated=1) (element-type GOptionEntry) a
+ *           %NULL-terminated list of #GOptionEntrys
  *
  * Adds main option entries to be handled by @application.
  *
@@ -667,7 +657,8 @@ g_application_add_main_option_entries (GApplication       *application,
 
   for (i = 0; entries[i].long_name; i++)
     {
-      GOptionEntry my_entries[2] = { entries[i], { NULL } };
+      GOptionEntry my_entries[2] = { { NULL }, { NULL } };
+      my_entries[0] = entries[i];
 
       if (!my_entries[0].arg_data)
         add_packed_option (application, &my_entries[0]);
@@ -677,6 +668,64 @@ g_application_add_main_option_entries (GApplication       *application,
 }
 
 /**
+ * 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,
+                               gint          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 },
+    { 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: a #GOptionGroup
@@ -699,9 +748,8 @@ g_application_add_main_option_entries (GApplication       *application,
  *
  * 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 <literal>--display=</literal>
- * or <literal>--gdk-debug=</literal> on future runs will have no effect
- * on the existing primary instance.
+ * 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
@@ -1026,6 +1074,10 @@ g_application_set_property (GObject      *object,
       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));
@@ -1093,6 +1145,10 @@ g_application_get_property (GObject    *object,
                          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));
@@ -1120,6 +1176,20 @@ g_application_constructed (GObject *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
@@ -1131,8 +1201,10 @@ g_application_finalize (GObject *object)
   if (application->priv->main_options)
     g_option_group_free (application->priv->main_options);
   if (application->priv->packed_options)
-    g_hash_table_unref (application->priv->packed_options);
-
+    {
+      g_slist_free_full (application->priv->option_strings, g_free);
+      g_hash_table_unref (application->priv->packed_options);
+    }
   if (application->priv->impl)
     g_application_impl_destroy (application->priv->impl);
   g_free (application->priv->id);
@@ -1221,6 +1293,12 @@ g_application_class_init (GApplicationClass *class)
                         G_TYPE_APPLICATION_FLAGS, G_APPLICATION_FLAGS_NONE,
                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (object_class, PROP_RESOURCE_BASE_PATH,
+    g_param_spec_string ("resource-base-path",
+                         P_("Resource base path"),
+                         P_("The base resource path for the application"),
+                         NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_property (object_class, PROP_IS_REGISTERED,
     g_param_spec_boolean ("is-registered",
                           P_("Is registered"),
@@ -1361,8 +1439,8 @@ g_application_class_init (GApplicationClass *class)
    * 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 <literal>--gapplication-service</literal> switch works properly
-   * (ie: no activation in that case).
+   * 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
@@ -1587,6 +1665,79 @@ g_application_set_flags (GApplication      *application,
 }
 
 /**
+ * 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.
+ *
+ * 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
  *
@@ -1749,6 +1900,7 @@ g_application_get_dbus_object_path (GApplication *application)
   return g_application_impl_get_dbus_object_path (application->priv->impl);
 }
 
+
 /* Register {{{1 */
 /**
  * g_application_register:
@@ -1885,6 +2037,7 @@ 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--;
 
@@ -1990,11 +2143,11 @@ g_application_open (GApplication  *application,
  * application can inspect the values of its #GOptionEntrys.
  *
  * #GApplication::handle-local-options is a good place to handle options
- * such as <literal>--version</literal>, 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.
+ * 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
@@ -2011,7 +2164,8 @@ g_application_open (GApplication  *application,
  * 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
- * <xref linkend="gapplication-example-cmdline2"/> for an example.
+ * [gapplication-example-cmdline2.c][gapplication-example-cmdline2]
+ * 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