2 * Copyright © 2013 Canonical Limited
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Ryan Lortie <desrt@desrt.ca>
24 #include <gio/gdesktopappinfo.h>
26 #include <glib/gi18n.h>
36 const gchar *description;
37 const gchar *synopsis;
43 const gchar *description;
46 static const struct help_topic topics[] = {
47 { "help", N_("Print help"),
51 { "version", N_("Print version"),
52 N_("Print version information and exit")
54 { "list-apps", N_("List applications"),
55 N_("List the installed D-Bus activatable applications (by .desktop files)")
57 { "launch", N_("Launch an application"),
58 N_("Launch the application (with optional files to open)"),
61 { "action", N_("Activate an action"),
62 N_("Invoke an action on the application"),
63 N_("APPID ACTION [PARAMETER]")
65 { "list-actions", N_("List available actions"),
66 N_("List static actions for an application (from .desktop file)"),
71 static const struct help_substvar substvars[] = {
72 { N_("COMMAND"), N_("The command to print detailed help for") },
73 { N_("APPID"), N_("Application identifier in D-Bus format (eg: org.example.viewer)") },
74 { N_("FILE"), N_("Optional relative or relative filenames, or URIs to open") },
75 { N_("ACTION"), N_("The action name to invoke") },
76 { N_("PARAMETER"), N_("Optional parameter to the action invocation, in GVariant format") }
80 app_help (gboolean requested,
83 const struct help_topic *topic = NULL;
86 string = g_string_new (NULL);
92 for (i = 0; i < G_N_ELEMENTS (topics); i++)
93 if (g_str_equal (topics[i].command, command))
98 g_string_printf (string, _("Unknown command %s\n\n"), command);
103 g_string_append (string, _("Usage:\n"));
110 g_string_append_printf (string, "\n %s %s %s\n\n", "gapplication",
111 topic->command, topic->synopsis ? _(topic->synopsis) : "");
112 g_string_append_printf (string, "%s\n\n", _(topic->description));
116 g_string_append (string, _("Arguments:\n"));
119 for (i = 0; i < G_N_ELEMENTS (substvars); i++)
120 if (strstr (topic->synopsis, substvars[i].var))
121 maxwidth = MAX(maxwidth, strlen (_(substvars[i].var)));
123 for (i = 0; i < G_N_ELEMENTS (substvars); i++)
124 if (strstr (topic->synopsis, substvars[i].var))
125 g_string_append_printf (string, " %-*.*s %s\n", maxwidth, maxwidth,
126 _(substvars[i].var), _(substvars[i].description));
127 g_string_append (string, "\n");
135 g_string_append_printf (string, "\n %s %s %s\n\n", "gapplication", _("COMMAND"), _("[ARGS...]"));
136 g_string_append_printf (string, _("Commands:\n"));
139 for (i = 0; i < G_N_ELEMENTS (topics); i++)
140 maxwidth = MAX(maxwidth, strlen (topics[i].command));
142 for (i = 0; i < G_N_ELEMENTS (topics); i++)
143 g_string_append_printf (string, " %-*.*s %s\n", maxwidth, maxwidth,
144 topics[i].command, _(topics[i].summary));
146 g_string_append (string, "\n");
147 /* Translators: do not translate 'help', but please translate 'COMMAND'. */
148 g_string_append_printf (string, _("Use '%s help COMMAND' to get detailed help.\n\n"), "gapplication");
152 g_print ("%s", string->str);
154 g_printerr ("%s\n", string->str);
156 g_string_free (string, TRUE);
158 return requested ? 0 : 1;
162 app_check_name (gchar **args,
163 const gchar *command)
167 g_printerr (_("%s command requires an application id to directly follow\n\n"), command);
171 if (!g_dbus_is_name (args[0]))
173 g_printerr (_("invalid application id: '%s'\n"), args[0]);
181 app_no_args (const gchar *command)
183 /* Translators: %s is replaced with a command name like 'list-actions' */
184 g_printerr (_("'%s' takes no arguments\n\n"), command);
185 return app_help (FALSE, command);
189 app_version (gchar **args)
191 if (g_strv_length (args))
192 return app_no_args ("version");
194 g_print (PACKAGE_VERSION "\n");
199 app_list (gchar **args)
203 if (g_strv_length (args))
204 return app_no_args ("list");
206 apps = g_app_info_get_all ();
210 GDesktopAppInfo *info = apps->data;
212 if (G_IS_DESKTOP_APP_INFO (info))
213 if (g_desktop_app_info_get_boolean (info, "DBusActivatable"))
215 const gchar *filename;
217 filename = g_app_info_get_id (G_APP_INFO (info));
218 if (g_str_has_suffix (filename, ".desktop"))
222 id = g_strndup (filename, strlen (filename) - 8);
223 g_print ("%s\n", id);
228 apps = g_list_delete_link (apps, apps);
229 g_object_unref (info);
236 app_path_for_id (const gchar *app_id)
241 path = g_strconcat ("/", app_id, NULL);
242 for (i = 0; path[i]; i++)
250 app_call (const gchar *app_id,
251 const gchar *method_name,
252 GVariant *parameters)
254 GDBusConnection *session;
255 GError *error = NULL;
260 session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
263 g_variant_unref (g_variant_ref_sink (parameters));
264 g_printerr (_("unable to connect to D-Bus: %s\n"), error->message);
265 g_error_free (error);
269 object_path = app_path_for_id (app_id);
271 result = g_dbus_connection_call_sync (session, app_id, object_path, "org.freedesktop.Application",
272 method_name, parameters, G_VARIANT_TYPE_UNIT,
273 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
275 g_free (object_path);
279 g_variant_unref (result);
284 g_printerr (_("error sending %s message to application: %s\n"), method_name, error->message);
285 g_error_free (error);
291 app_get_platform_data (void)
293 GVariantBuilder builder;
294 const gchar *startup_id;
296 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
298 if ((startup_id = g_getenv ("DESKTOP_STARTUP_iD")))
299 g_variant_builder_add (&builder, "{sv}", "desktop-startup-id", g_variant_new_string (startup_id));
301 return g_variant_builder_end (&builder);
305 app_action (gchar **args)
307 GVariantBuilder params;
310 if (!app_check_name (args, "action"))
315 g_printerr (_("action name must be given after application id\n"));
321 if (!g_action_name_is_valid (name))
323 g_printerr (_("invalid action name: '%s'\n"
324 "action names must consist of only alphanumerics, '-' and '.'\n"), name);
328 g_variant_builder_init (¶ms, G_VARIANT_TYPE ("av"));
332 GError *error = NULL;
335 parameter = g_variant_parse (NULL, args[2], NULL, NULL, &error);
339 g_printerr (_("error parsing action parameter: %s\n"), error->message);
340 g_variant_builder_clear (¶ms);
341 g_error_free (error);
345 g_variant_builder_add (¶ms, "v", parameter);
346 g_variant_unref (parameter);
350 g_printerr (_("actions accept a maximum of one parameter\n"));
351 g_variant_builder_clear (¶ms);
356 return app_call (args[0], "ActivateAction", g_variant_new ("(sav@a{sv})", name, ¶ms, app_get_platform_data ()));
360 app_activate (const gchar *app_id)
362 return app_call (app_id, "Activate", g_variant_new ("(@a{sv})", app_get_platform_data ()));
366 app_launch (gchar **args)
368 GVariantBuilder files;
371 if (!app_check_name (args, "launch"))
375 return app_activate (args[0]);
377 g_variant_builder_init (&files, G_VARIANT_TYPE_STRING_ARRAY);
379 for (i = 1; args[i]; i++)
383 /* "This operation never fails" */
384 file = g_file_new_for_commandline_arg (args[i]);
385 g_variant_builder_add_value (&files, g_variant_new_take_string (g_file_get_uri (file)));
386 g_object_unref (file);
389 return app_call (args[0], "Open", g_variant_new ("(as@a{sv})", &files, app_get_platform_data ()));
393 app_list_actions (gchar **args)
395 const gchar * const *actions;
396 GDesktopAppInfo *app_info;
400 if (!app_check_name (args, "list-actions"))
405 g_printerr (_("list-actions command takes only the application id"));
406 app_help (FALSE, "list-actions");
409 filename = g_strconcat (args[0], ".desktop", NULL);
410 app_info = g_desktop_app_info_new (filename);
413 if (app_info == NULL)
415 g_printerr (_("unable to find desktop file for application %s\n"), args[0]);
419 actions = g_desktop_app_info_list_actions (app_info);
421 for (i = 0; actions[i]; i++)
422 g_print ("%s\n", actions[i]);
424 g_object_unref (app_info);
430 main (int argc, char **argv)
432 setlocale (LC_ALL, "");
433 textdomain (GETTEXT_PACKAGE);
434 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
435 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
436 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
440 return app_help (TRUE, NULL);
442 if (g_str_equal (argv[1], "help"))
443 return app_help (TRUE, argv[2]);
445 if (g_str_equal (argv[1], "version"))
446 return app_version (argv + 2);
448 if (g_str_equal (argv[1], "list-apps"))
449 return app_list (argv + 2);
451 if (g_str_equal (argv[1], "launch"))
452 return app_launch (argv + 2);
454 if (g_str_equal (argv[1], "action"))
455 return app_action (argv + 2);
457 if (g_str_equal (argv[1], "list-actions"))
458 return app_list_actions (argv + 2);
460 g_printerr (_("unrecognised command: %s\n\n"), argv[1]);
462 return app_help (FALSE, NULL);