valgrind: Add more suppressions to glib.supp
[glib.git] / gio / gapplication-tool.c
blob68a7424197050ffefea33f0bcacff77cd75e995e
1 /*
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.1 of the License, 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, see <http://www.gnu.org/licenses/>.
17 * Author: Ryan Lortie <desrt@desrt.ca>
20 #include "config.h"
22 #include <gio/gdesktopappinfo.h>
24 #include <glib/gi18n.h>
25 #include <gio/gio.h>
27 #include <string.h>
28 #include <locale.h>
30 struct help_topic
32 const gchar *command;
33 const gchar *summary;
34 const gchar *description;
35 const gchar *synopsis;
38 struct help_substvar
40 const gchar *var;
41 const gchar *description;
44 static const struct help_topic topics[] = {
45 { "help", N_("Print help"),
46 N_("Print help"),
47 N_("[COMMAND]")
49 { "version", N_("Print version"),
50 N_("Print version information and exit")
52 { "list-apps", N_("List applications"),
53 N_("List the installed D-Bus activatable applications (by .desktop files)")
55 { "launch", N_("Launch an application"),
56 N_("Launch the application (with optional files to open)"),
57 N_("APPID [FILE…]")
59 { "action", N_("Activate an action"),
60 N_("Invoke an action on the application"),
61 N_("APPID ACTION [PARAMETER]")
63 { "list-actions", N_("List available actions"),
64 N_("List static actions for an application (from .desktop file)"),
65 N_("APPID")
69 static const struct help_substvar substvars[] = {
70 { N_("COMMAND"), N_("The command to print detailed help for") },
71 { N_("APPID"), N_("Application identifier in D-Bus format (eg: org.example.viewer)") },
72 { N_("FILE"), N_("Optional relative or absolute filenames, or URIs to open") },
73 { N_("ACTION"), N_("The action name to invoke") },
74 { N_("PARAMETER"), N_("Optional parameter to the action invocation, in GVariant format") }
77 static int
78 app_help (gboolean requested,
79 const gchar *command)
81 const struct help_topic *topic = NULL;
82 GString *string;
84 string = g_string_new (NULL);
86 if (command)
88 gint i;
90 for (i = 0; i < G_N_ELEMENTS (topics); i++)
91 if (g_str_equal (topics[i].command, command))
92 topic = &topics[i];
94 if (!topic)
96 g_string_printf (string, _("Unknown command %s\n\n"), command);
97 requested = FALSE;
101 g_string_append (string, _("Usage:\n"));
103 if (topic)
105 gint maxwidth;
106 gint i;
108 g_string_append_printf (string, "\n %s %s %s\n\n", "gapplication",
109 topic->command, topic->synopsis ? _(topic->synopsis) : "");
110 g_string_append_printf (string, "%s\n\n", _(topic->description));
112 if (topic->synopsis)
114 g_string_append (string, _("Arguments:\n"));
116 maxwidth = 0;
117 for (i = 0; i < G_N_ELEMENTS (substvars); i++)
118 if (strstr (topic->synopsis, substvars[i].var))
119 maxwidth = MAX(maxwidth, strlen (_(substvars[i].var)));
121 for (i = 0; i < G_N_ELEMENTS (substvars); i++)
122 if (strstr (topic->synopsis, substvars[i].var))
123 g_string_append_printf (string, " %-*.*s %s\n", maxwidth, maxwidth,
124 _(substvars[i].var), _(substvars[i].description));
125 g_string_append (string, "\n");
128 else
130 gint maxwidth;
131 gint i;
133 g_string_append_printf (string, "\n %s %s %s\n\n", "gapplication", _("COMMAND"), _("[ARGS…]"));
134 g_string_append_printf (string, _("Commands:\n"));
136 maxwidth = 0;
137 for (i = 0; i < G_N_ELEMENTS (topics); i++)
138 maxwidth = MAX(maxwidth, strlen (topics[i].command));
140 for (i = 0; i < G_N_ELEMENTS (topics); i++)
141 g_string_append_printf (string, " %-*.*s %s\n", maxwidth, maxwidth,
142 topics[i].command, _(topics[i].summary));
144 g_string_append (string, "\n");
145 /* Translators: do not translate 'help', but please translate 'COMMAND'. */
146 g_string_append_printf (string, _("Use “%s help COMMAND” to get detailed help.\n\n"), "gapplication");
149 if (requested)
150 g_print ("%s", string->str);
151 else
152 g_printerr ("%s\n", string->str);
154 g_string_free (string, TRUE);
156 return requested ? 0 : 1;
159 static gboolean
160 app_check_name (gchar **args,
161 const gchar *command)
163 if (args[0] == NULL)
165 g_printerr (_("%s command requires an application id to directly follow\n\n"), command);
166 return FALSE;
169 if (!g_dbus_is_name (args[0]))
171 g_printerr (_("invalid application id: “%s”\n"), args[0]);
172 return FALSE;
175 return TRUE;
178 static int
179 app_no_args (const gchar *command)
181 /* Translators: %s is replaced with a command name like 'list-actions' */
182 g_printerr (_("“%s” takes no arguments\n\n"), command);
183 return app_help (FALSE, command);
186 static int
187 app_version (gchar **args)
189 if (g_strv_length (args))
190 return app_no_args ("version");
192 g_print (PACKAGE_VERSION "\n");
193 return 0;
196 static int
197 app_list (gchar **args)
199 GList *apps;
201 if (g_strv_length (args))
202 return app_no_args ("list");
204 apps = g_app_info_get_all ();
206 while (apps)
208 GDesktopAppInfo *info = apps->data;
210 if (G_IS_DESKTOP_APP_INFO (info))
211 if (g_desktop_app_info_get_boolean (info, "DBusActivatable"))
213 const gchar *filename;
215 filename = g_app_info_get_id (G_APP_INFO (info));
216 if (g_str_has_suffix (filename, ".desktop"))
218 gchar *id;
220 id = g_strndup (filename, strlen (filename) - 8);
221 g_print ("%s\n", id);
222 g_free (id);
226 apps = g_list_delete_link (apps, apps);
227 g_object_unref (info);
230 return 0;
233 static gchar *
234 app_path_for_id (const gchar *app_id)
236 gchar *path;
237 gint i;
239 path = g_strconcat ("/", app_id, NULL);
240 for (i = 0; path[i]; i++)
242 if (path[i] == '.')
243 path[i] = '/';
244 if (path[i] == '-')
245 path[i] = '_';
248 return path;
251 static int
252 app_call (const gchar *app_id,
253 const gchar *method_name,
254 GVariant *parameters)
256 GDBusConnection *session;
257 GError *error = NULL;
258 gchar *object_path;
259 GVariant *result;
262 session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
263 if (!session)
265 g_variant_unref (g_variant_ref_sink (parameters));
266 g_printerr (_("unable to connect to D-Bus: %s\n"), error->message);
267 g_error_free (error);
268 return 1;
271 object_path = app_path_for_id (app_id);
273 result = g_dbus_connection_call_sync (session, app_id, object_path, "org.freedesktop.Application",
274 method_name, parameters, G_VARIANT_TYPE_UNIT,
275 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
277 g_free (object_path);
279 if (result)
281 g_variant_unref (result);
282 return 0;
284 else
286 g_printerr (_("error sending %s message to application: %s\n"), method_name, error->message);
287 g_error_free (error);
288 return 1;
292 static GVariant *
293 app_get_platform_data (void)
295 GVariantBuilder builder;
296 const gchar *startup_id;
298 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
300 if ((startup_id = g_getenv ("DESKTOP_STARTUP_ID")))
301 g_variant_builder_add (&builder, "{sv}", "desktop-startup-id", g_variant_new_string (startup_id));
303 return g_variant_builder_end (&builder);
306 static int
307 app_action (gchar **args)
309 GVariantBuilder params;
310 const gchar *name;
312 if (!app_check_name (args, "action"))
313 return 1;
315 if (args[1] == NULL)
317 g_printerr (_("action name must be given after application id\n"));
318 return 1;
321 name = args[1];
323 if (!g_action_name_is_valid (name))
325 g_printerr (_("invalid action name: “%s”\n"
326 "action names must consist of only alphanumerics, “-” and “.”\n"), name);
327 return 1;
330 g_variant_builder_init (&params, G_VARIANT_TYPE ("av"));
332 if (args[2])
334 GError *error = NULL;
335 GVariant *parameter;
337 parameter = g_variant_parse (NULL, args[2], NULL, NULL, &error);
339 if (!parameter)
341 gchar *context;
343 context = g_variant_parse_error_print_context (error, args[2]);
344 g_printerr (_("error parsing action parameter: %s\n"), context);
345 g_variant_builder_clear (&params);
346 g_error_free (error);
347 g_free (context);
348 return 1;
351 g_variant_builder_add (&params, "v", parameter);
352 g_variant_unref (parameter);
354 if (args[3])
356 g_printerr (_("actions accept a maximum of one parameter\n"));
357 g_variant_builder_clear (&params);
358 return 1;
362 return app_call (args[0], "ActivateAction", g_variant_new ("(sav@a{sv})", name, &params, app_get_platform_data ()));
365 static int
366 app_activate (const gchar *app_id)
368 return app_call (app_id, "Activate", g_variant_new ("(@a{sv})", app_get_platform_data ()));
371 static int
372 app_launch (gchar **args)
374 GVariantBuilder files;
375 gint i;
377 if (!app_check_name (args, "launch"))
378 return 1;
380 if (args[1] == NULL)
381 return app_activate (args[0]);
383 g_variant_builder_init (&files, G_VARIANT_TYPE_STRING_ARRAY);
385 for (i = 1; args[i]; i++)
387 GFile *file;
389 /* "This operation never fails" */
390 file = g_file_new_for_commandline_arg (args[i]);
391 g_variant_builder_add_value (&files, g_variant_new_take_string (g_file_get_uri (file)));
392 g_object_unref (file);
395 return app_call (args[0], "Open", g_variant_new ("(as@a{sv})", &files, app_get_platform_data ()));
398 static int
399 app_list_actions (gchar **args)
401 const gchar * const *actions;
402 GDesktopAppInfo *app_info;
403 gchar *filename;
404 gint i;
406 if (!app_check_name (args, "list-actions"))
407 return 1;
409 if (args[1])
411 g_printerr (_("list-actions command takes only the application id"));
412 app_help (FALSE, "list-actions");
415 filename = g_strconcat (args[0], ".desktop", NULL);
416 app_info = g_desktop_app_info_new (filename);
417 g_free (filename);
419 if (app_info == NULL)
421 g_printerr (_("unable to find desktop file for application %s\n"), args[0]);
422 return 1;
425 actions = g_desktop_app_info_list_actions (app_info);
427 for (i = 0; actions[i]; i++)
428 g_print ("%s\n", actions[i]);
430 g_object_unref (app_info);
432 return 0;
436 main (int argc, char **argv)
438 setlocale (LC_ALL, "");
439 textdomain (GETTEXT_PACKAGE);
440 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
441 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
442 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
443 #endif
445 if (argc < 2)
446 return app_help (TRUE, NULL);
448 if (g_str_equal (argv[1], "help"))
449 return app_help (TRUE, argv[2]);
451 if (g_str_equal (argv[1], "version"))
452 return app_version (argv + 2);
454 if (g_str_equal (argv[1], "list-apps"))
455 return app_list (argv + 2);
457 if (g_str_equal (argv[1], "launch"))
458 return app_launch (argv + 2);
460 if (g_str_equal (argv[1], "action"))
461 return app_action (argv + 2);
463 if (g_str_equal (argv[1], "list-actions"))
464 return app_list_actions (argv + 2);
466 g_printerr (_("unrecognised command: %s\n\n"), argv[1]);
468 return app_help (FALSE, NULL);