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>
22 #include <gio/gdesktopappinfo.h>
24 #include <glib/gi18n.h>
34 const gchar
*description
;
35 const gchar
*synopsis
;
41 const gchar
*description
;
44 static const struct help_topic topics
[] = {
45 { "help", N_("Print help"),
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)"),
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)"),
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") }
78 app_help (gboolean requested
,
81 const struct help_topic
*topic
= NULL
;
84 string
= g_string_new (NULL
);
90 for (i
= 0; i
< G_N_ELEMENTS (topics
); i
++)
91 if (g_str_equal (topics
[i
].command
, command
))
96 g_string_printf (string
, _("Unknown command %s\n\n"), command
);
101 g_string_append (string
, _("Usage:\n"));
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
));
114 g_string_append (string
, _("Arguments:\n"));
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");
133 g_string_append_printf (string
, "\n %s %s %s\n\n", "gapplication", _("COMMAND"), _("[ARGS…]"));
134 g_string_append_printf (string
, _("Commands:\n"));
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");
150 g_print ("%s", string
->str
);
152 g_printerr ("%s\n", string
->str
);
154 g_string_free (string
, TRUE
);
156 return requested
? 0 : 1;
160 app_check_name (gchar
**args
,
161 const gchar
*command
)
165 g_printerr (_("%s command requires an application id to directly follow\n\n"), command
);
169 if (!g_dbus_is_name (args
[0]))
171 g_printerr (_("invalid application id: “%s”\n"), args
[0]);
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
);
187 app_version (gchar
**args
)
189 if (g_strv_length (args
))
190 return app_no_args ("version");
192 g_print (PACKAGE_VERSION
"\n");
197 app_list (gchar
**args
)
201 if (g_strv_length (args
))
202 return app_no_args ("list");
204 apps
= g_app_info_get_all ();
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"))
220 id
= g_strndup (filename
, strlen (filename
) - 8);
221 g_print ("%s\n", id
);
226 apps
= g_list_delete_link (apps
, apps
);
227 g_object_unref (info
);
234 app_path_for_id (const gchar
*app_id
)
239 path
= g_strconcat ("/", app_id
, NULL
);
240 for (i
= 0; path
[i
]; i
++)
252 app_call (const gchar
*app_id
,
253 const gchar
*method_name
,
254 GVariant
*parameters
)
256 GDBusConnection
*session
;
257 GError
*error
= NULL
;
262 session
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, &error
);
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
);
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
);
281 g_variant_unref (result
);
286 g_printerr (_("error sending %s message to application: %s\n"), method_name
, error
->message
);
287 g_error_free (error
);
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
);
307 app_action (gchar
**args
)
309 GVariantBuilder params
;
312 if (!app_check_name (args
, "action"))
317 g_printerr (_("action name must be given after application id\n"));
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
);
330 g_variant_builder_init (¶ms
, G_VARIANT_TYPE ("av"));
334 GError
*error
= NULL
;
337 parameter
= g_variant_parse (NULL
, args
[2], NULL
, NULL
, &error
);
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 (¶ms
);
346 g_error_free (error
);
351 g_variant_builder_add (¶ms
, "v", parameter
);
352 g_variant_unref (parameter
);
356 g_printerr (_("actions accept a maximum of one parameter\n"));
357 g_variant_builder_clear (¶ms
);
362 return app_call (args
[0], "ActivateAction", g_variant_new ("(sav@a{sv})", name
, ¶ms
, app_get_platform_data ()));
366 app_activate (const gchar
*app_id
)
368 return app_call (app_id
, "Activate", g_variant_new ("(@a{sv})", app_get_platform_data ()));
372 app_launch (gchar
**args
)
374 GVariantBuilder files
;
377 if (!app_check_name (args
, "launch"))
381 return app_activate (args
[0]);
383 g_variant_builder_init (&files
, G_VARIANT_TYPE_STRING_ARRAY
);
385 for (i
= 1; args
[i
]; i
++)
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 ()));
399 app_list_actions (gchar
**args
)
401 const gchar
* const *actions
;
402 GDesktopAppInfo
*app_info
;
406 if (!app_check_name (args
, "list-actions"))
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
);
419 if (app_info
== NULL
)
421 g_printerr (_("unable to find desktop file for application %s\n"), args
[0]);
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
);
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");
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
);