diff --git a/gio/gapplication.c b/gio/gapplication.c index 55e7f299c..b7d2870e9 100644 --- a/gio/gapplication.c +++ b/gio/gapplication.c @@ -227,6 +227,7 @@ struct _GApplicationPrivate { GApplicationFlags flags; gchar *id; + gchar *version; gchar *resource_path; GActionGroup *actions; @@ -264,6 +265,7 @@ enum { PROP_NONE, PROP_APPLICATION_ID, + PROP_VERSION, PROP_FLAGS, PROP_RESOURCE_BASE_PATH, PROP_IS_REGISTERED, @@ -478,11 +480,13 @@ g_application_pack_option_entries (GApplication *application, 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; @@ -564,6 +568,17 @@ g_application_parse_command_line (GApplication *application, 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) { @@ -580,6 +595,8 @@ g_application_parse_command_line (GApplication *application, 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; @@ -1101,8 +1118,9 @@ g_application_real_local_command_line (GApplication *application, GError *error = NULL; GVariantDict *options; gint n_args; + gboolean print_version = FALSE; - options = g_application_parse_command_line (application, arguments, &error); + options = g_application_parse_command_line (application, arguments, &print_version, &error); if (!options) { g_printerr ("%s\n", error->message); @@ -1111,6 +1129,21 @@ g_application_real_local_command_line (GApplication *application, 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) @@ -1236,6 +1269,10 @@ g_application_set_property (GObject *object, 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; @@ -1306,6 +1343,11 @@ g_application_get_property (GObject *object, 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)); @@ -1401,6 +1443,7 @@ g_application_finalize (GObject *object) 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); @@ -1496,6 +1539,18 @@ g_application_class_init (GApplicationClass *class) 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: * @@ -1887,6 +1942,50 @@ g_application_set_application_id (GApplication *application, } } +/** + * 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 diff --git a/gio/gapplication.h b/gio/gapplication.h index cb6b90867..6df0bb4ff 100644 --- a/gio/gapplication.h +++ b/gio/gapplication.h @@ -139,6 +139,12 @@ GIO_AVAILABLE_IN_ALL void g_application_set_application_id (GApplication *application, const gchar *application_id); +GIO_AVAILABLE_IN_2_80 +const gchar * g_application_get_version (GApplication *application); +GIO_AVAILABLE_IN_2_80 +void g_application_set_version (GApplication *application, + const gchar *version); + GIO_AVAILABLE_IN_2_34 GDBusConnection * g_application_get_dbus_connection (GApplication *application); GIO_AVAILABLE_IN_2_34 diff --git a/gio/tests/gapplication-example-cmdline.c b/gio/tests/gapplication-example-cmdline.c index 99380cd78..cbec9a8bb 100644 --- a/gio/tests/gapplication-example-cmdline.c +++ b/gio/tests/gapplication-example-cmdline.c @@ -34,6 +34,7 @@ main (int argc, char **argv) G_APPLICATION_HANDLES_COMMAND_LINE); g_signal_connect (app, "command-line", G_CALLBACK (command_line), NULL); g_application_set_inactivity_timeout (app, 10000); + g_application_set_version (app, "2.3"); status = g_application_run (app, argc, argv); diff --git a/gio/tests/gapplication.c b/gio/tests/gapplication.c index 29c69896f..8c1dac10c 100644 --- a/gio/tests/gapplication.c +++ b/gio/tests/gapplication.c @@ -369,6 +369,7 @@ properties (void) GDBusConnection *c; GObject *app; gchar *id; + gchar *version; GApplicationFlags flags; gboolean registered; guint timeout; @@ -381,20 +382,25 @@ properties (void) app = g_object_new (G_TYPE_APPLICATION, "application-id", "org.gtk.TestApplication", + "version", "1.0", NULL); g_object_get (app, "application-id", &id, + "version", &version, "flags", &flags, "is-registered", ®istered, "inactivity-timeout", &timeout, NULL); g_assert_cmpstr (id, ==, "org.gtk.TestApplication"); + g_assert_cmpstr (version, ==, "1.0"); g_assert_cmpint (flags, ==, G_APPLICATION_DEFAULT_FLAGS); g_assert (!registered); g_assert_cmpint (timeout, ==, 0); + g_clear_pointer (&version, g_free); + ret = g_application_register (G_APPLICATION (app), NULL, &error); g_assert (ret); g_assert_no_error (error); @@ -1085,6 +1091,37 @@ test_api (void) g_object_unref (app); } +static void +test_version (void) +{ + GApplication *app; + gchar *version = NULL; + gchar *version_orig = NULL; + + app = g_application_new ("org.gtk.TestApplication", 0); + + version_orig = "1.2"; + g_object_set (G_OBJECT (app), "version", version_orig, NULL); + g_object_get (app, "version", &version, NULL); + g_assert_cmpstr (version, ==, version_orig); + g_free (version); + + /* test attempting to set the same version again */ + version_orig = "1.2"; + g_object_set (G_OBJECT (app), "version", version_orig, NULL); + g_object_get (app, "version", &version, NULL); + g_assert_cmpstr (version, ==, version_orig); + g_free (version); + + version_orig = "2.4"; + g_object_set (G_OBJECT (app), "version", version_orig, NULL); + g_object_get (app, "version", &version, NULL); + g_assert_cmpstr (version, ==, version_orig); + g_free (version); + + g_object_unref (app); +} + /* Check that G_APPLICATION_ALLOW_REPLACEMENT works. To do so, we launch * a GApplication in this process that allows replacement, and then * launch a subprocess with --gapplication-replace. We have to do our @@ -1830,6 +1867,7 @@ main (int argc, char **argv) g_test_add_func ("/gapplication/test-handle-local-options2", test_handle_local_options_failure); g_test_add_func ("/gapplication/test-handle-local-options3", test_handle_local_options_passthrough); g_test_add_func ("/gapplication/api", test_api); + g_test_add_func ("/gapplication/version", test_version); g_test_add_data_func ("/gapplication/replace", GINT_TO_POINTER (TRUE), test_replace); g_test_add_data_func ("/gapplication/no-replace", GINT_TO_POINTER (FALSE), test_replace); g_test_add_func ("/gapplication/dbus/activate", test_dbus_activate);