Blame gio/gapplication-tool.c

Packit Service d3d246
/*
Packit Service d3d246
 * Copyright © 2013 Canonical Limited
Packit Service d3d246
 *
Packit Service d3d246
 * This library is free software; you can redistribute it and/or
Packit Service d3d246
 * modify it under the terms of the GNU Lesser General Public
Packit Service d3d246
 * License as published by the Free Software Foundation; either
Packit Service d3d246
 * version 2.1 of the License, or (at your option) any later version.
Packit Service d3d246
 *
Packit Service d3d246
 * This library is distributed in the hope that it will be useful,
Packit Service d3d246
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d3d246
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service d3d246
 * Lesser General Public License for more details.
Packit Service d3d246
 *
Packit Service d3d246
 * You should have received a copy of the GNU Lesser General Public
Packit Service d3d246
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit Service d3d246
 *
Packit Service d3d246
 * Author: Ryan Lortie <desrt@desrt.ca>
Packit Service d3d246
 */
Packit Service d3d246
Packit Service d3d246
#include "config.h"
Packit Service d3d246
Packit Service d3d246
#include <gio/gdesktopappinfo.h>
Packit Service d3d246
Packit Service d3d246
#include <glib/gi18n.h>
Packit Service d3d246
#include <gio/gio.h>
Packit Service d3d246
Packit Service d3d246
#include <string.h>
Packit Service d3d246
#include <locale.h>
Packit Service d3d246
Packit Service d3d246
struct help_topic
Packit Service d3d246
{
Packit Service d3d246
  const gchar *command;
Packit Service d3d246
  const gchar *summary;
Packit Service d3d246
  const gchar *description;
Packit Service d3d246
  const gchar *synopsis;
Packit Service d3d246
};
Packit Service d3d246
Packit Service d3d246
struct help_substvar
Packit Service d3d246
{
Packit Service d3d246
  const gchar *var;
Packit Service d3d246
  const gchar *description;
Packit Service d3d246
};
Packit Service d3d246
Packit Service d3d246
static const struct help_topic topics[] = {
Packit Service d3d246
  { "help",         N_("Print help"),
Packit Service d3d246
                    N_("Print help"),
Packit Service d3d246
                    N_("[COMMAND]")
Packit Service d3d246
  },
Packit Service d3d246
  { "version",      N_("Print version"),
Packit Service d3d246
                    N_("Print version information and exit")
Packit Service d3d246
  },
Packit Service d3d246
  { "list-apps",    N_("List applications"),
Packit Service d3d246
                    N_("List the installed D-Bus activatable applications (by .desktop files)")
Packit Service d3d246
  },
Packit Service d3d246
  { "launch",       N_("Launch an application"),
Packit Service d3d246
                    N_("Launch the application (with optional files to open)"),
Packit Service d3d246
                    N_("APPID [FILE…]")
Packit Service d3d246
  },
Packit Service d3d246
  { "action",       N_("Activate an action"),
Packit Service d3d246
                    N_("Invoke an action on the application"),
Packit Service d3d246
                    N_("APPID ACTION [PARAMETER]")
Packit Service d3d246
  },
Packit Service d3d246
  { "list-actions", N_("List available actions"),
Packit Service d3d246
                    N_("List static actions for an application (from .desktop file)"),
Packit Service d3d246
                    N_("APPID")
Packit Service d3d246
  }
Packit Service d3d246
};
Packit Service d3d246
Packit Service d3d246
static const struct help_substvar substvars[] = {
Packit Service d3d246
  { N_("COMMAND"),   N_("The command to print detailed help for")                             },
Packit Service d3d246
  { N_("APPID"),     N_("Application identifier in D-Bus format (eg: org.example.viewer)")    },
Packit Service d3d246
  { N_("FILE"),      N_("Optional relative or absolute filenames, or URIs to open")           },
Packit Service d3d246
  { N_("ACTION"),    N_("The action name to invoke")                                          },
Packit Service d3d246
  { N_("PARAMETER"), N_("Optional parameter to the action invocation, in GVariant format")    }
Packit Service d3d246
};
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_help (gboolean     requested,
Packit Service d3d246
          const gchar *command)
Packit Service d3d246
{
Packit Service d3d246
  const struct help_topic *topic = NULL;
Packit Service d3d246
  GString *string;
Packit Service d3d246
Packit Service d3d246
  string = g_string_new (NULL);
Packit Service d3d246
Packit Service d3d246
  if (command)
Packit Service d3d246
    {
Packit Service d3d246
      gint i;
Packit Service d3d246
Packit Service d3d246
      for (i = 0; i < G_N_ELEMENTS (topics); i++)
Packit Service d3d246
        if (g_str_equal (topics[i].command, command))
Packit Service d3d246
          topic = &topics[i];
Packit Service d3d246
Packit Service d3d246
      if (!topic)
Packit Service d3d246
        {
Packit Service d3d246
          g_string_printf (string, _("Unknown command %s\n\n"), command);
Packit Service d3d246
          requested = FALSE;
Packit Service d3d246
        }
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  g_string_append (string, _("Usage:\n"));
Packit Service d3d246
Packit Service d3d246
  if (topic)
Packit Service d3d246
    {
Packit Service d3d246
      gint maxwidth;
Packit Service d3d246
      gint i;
Packit Service d3d246
Packit Service d3d246
      g_string_append_printf (string, "\n  %s %s %s\n\n", "gapplication",
Packit Service d3d246
                              topic->command, topic->synopsis ? _(topic->synopsis) : "");
Packit Service d3d246
      g_string_append_printf (string, "%s\n\n", _(topic->description));
Packit Service d3d246
Packit Service d3d246
      if (topic->synopsis)
Packit Service d3d246
        {
Packit Service d3d246
          g_string_append (string, _("Arguments:\n"));
Packit Service d3d246
Packit Service d3d246
          maxwidth = 0;
Packit Service d3d246
          for (i = 0; i < G_N_ELEMENTS (substvars); i++)
Packit Service d3d246
            if (strstr (topic->synopsis, substvars[i].var))
Packit Service d3d246
              maxwidth = MAX(maxwidth, strlen (_(substvars[i].var)));
Packit Service d3d246
Packit Service d3d246
          for (i = 0; i < G_N_ELEMENTS (substvars); i++)
Packit Service d3d246
            if (strstr (topic->synopsis, substvars[i].var))
Packit Service d3d246
              g_string_append_printf (string, "  %-*.*s   %s\n", maxwidth, maxwidth,
Packit Service d3d246
                                      _(substvars[i].var), _(substvars[i].description));
Packit Service d3d246
          g_string_append (string, "\n");
Packit Service d3d246
        }
Packit Service d3d246
    }
Packit Service d3d246
  else
Packit Service d3d246
    {
Packit Service d3d246
      gint maxwidth;
Packit Service d3d246
      gint i;
Packit Service d3d246
Packit Service d3d246
      g_string_append_printf (string, "\n  %s %s %s\n\n", "gapplication", _("COMMAND"), _("[ARGS…]"));
Packit Service d3d246
      g_string_append_printf (string, _("Commands:\n"));
Packit Service d3d246
Packit Service d3d246
      maxwidth = 0;
Packit Service d3d246
      for (i = 0; i < G_N_ELEMENTS (topics); i++)
Packit Service d3d246
        maxwidth = MAX(maxwidth, strlen (topics[i].command));
Packit Service d3d246
Packit Service d3d246
      for (i = 0; i < G_N_ELEMENTS (topics); i++)
Packit Service d3d246
        g_string_append_printf (string, "  %-*.*s   %s\n", maxwidth, maxwidth,
Packit Service d3d246
                                topics[i].command, _(topics[i].summary));
Packit Service d3d246
Packit Service d3d246
      g_string_append (string, "\n");
Packit Service d3d246
      /* Translators: do not translate 'help', but please translate 'COMMAND'. */
Packit Service d3d246
      g_string_append_printf (string, _("Use “%s help COMMAND” to get detailed help.\n\n"), "gapplication");
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  if (requested)
Packit Service d3d246
    g_print ("%s", string->str);
Packit Service d3d246
  else
Packit Service d3d246
    g_printerr ("%s\n", string->str);
Packit Service d3d246
Packit Service d3d246
  g_string_free (string, TRUE);
Packit Service d3d246
Packit Service d3d246
  return requested ? 0 : 1;
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static gboolean
Packit Service d3d246
app_check_name (gchar       **args,
Packit Service d3d246
                const gchar  *command)
Packit Service d3d246
{
Packit Service d3d246
  if (args[0] == NULL)
Packit Service d3d246
    {
Packit Service d3d246
      g_printerr (_("%s command requires an application id to directly follow\n\n"), command);
Packit Service d3d246
      return FALSE;
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  if (!g_dbus_is_name (args[0]))
Packit Service d3d246
    {
Packit Service d3d246
      g_printerr (_("invalid application id: “%s”\n"), args[0]);
Packit Service d3d246
      return FALSE;
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  return TRUE;
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_no_args (const gchar *command)
Packit Service d3d246
{
Packit Service d3d246
  /* Translators: %s is replaced with a command name like 'list-actions' */
Packit Service d3d246
  g_printerr (_("“%s” takes no arguments\n\n"), command);
Packit Service d3d246
  return app_help (FALSE, command);
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_version (gchar **args)
Packit Service d3d246
{
Packit Service d3d246
  if (g_strv_length (args))
Packit Service d3d246
    return app_no_args ("version");
Packit Service d3d246
Packit Service d3d246
  g_print (PACKAGE_VERSION "\n");
Packit Service d3d246
  return 0;
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_list (gchar **args)
Packit Service d3d246
{
Packit Service d3d246
  GList *apps;
Packit Service d3d246
Packit Service d3d246
  if (g_strv_length (args))
Packit Service d3d246
    return app_no_args ("list");
Packit Service d3d246
Packit Service d3d246
  apps = g_app_info_get_all ();
Packit Service d3d246
Packit Service d3d246
  while (apps)
Packit Service d3d246
    {
Packit Service d3d246
      GDesktopAppInfo *info = apps->data;
Packit Service d3d246
Packit Service d3d246
      if (G_IS_DESKTOP_APP_INFO (info))
Packit Service d3d246
        if (g_desktop_app_info_get_boolean (info, "DBusActivatable"))
Packit Service d3d246
          {
Packit Service d3d246
            const gchar *filename;
Packit Service d3d246
Packit Service d3d246
            filename = g_app_info_get_id (G_APP_INFO (info));
Packit Service d3d246
            if (g_str_has_suffix (filename, ".desktop"))
Packit Service d3d246
              {
Packit Service d3d246
                gchar *id;
Packit Service d3d246
Packit Service d3d246
                id = g_strndup (filename, strlen (filename) - 8);
Packit Service d3d246
                g_print ("%s\n", id);
Packit Service d3d246
                g_free (id);
Packit Service d3d246
              }
Packit Service d3d246
          }
Packit Service d3d246
Packit Service d3d246
      apps = g_list_delete_link (apps, apps);
Packit Service d3d246
      g_object_unref (info);
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  return 0;
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static gchar *
Packit Service d3d246
app_path_for_id (const gchar *app_id)
Packit Service d3d246
{
Packit Service d3d246
  gchar *path;
Packit Service d3d246
  gint i;
Packit Service d3d246
Packit Service d3d246
  path = g_strconcat ("/", app_id, NULL);
Packit Service d3d246
  for (i = 0; path[i]; i++)
Packit Service d3d246
    {
Packit Service d3d246
      if (path[i] == '.')
Packit Service d3d246
        path[i] = '/';
Packit Service d3d246
      if (path[i] == '-')
Packit Service d3d246
        path[i] = '_';
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  return path;
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_call (const gchar *app_id,
Packit Service d3d246
          const gchar *method_name,
Packit Service d3d246
          GVariant    *parameters)
Packit Service d3d246
{
Packit Service d3d246
  GDBusConnection *session;
Packit Service d3d246
  GError *error = NULL;
Packit Service d3d246
  gchar *object_path;
Packit Service d3d246
  GVariant *result;
Packit Service d3d246
Packit Service d3d246
Packit Service d3d246
  session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
Packit Service d3d246
  if (!session)
Packit Service d3d246
    {
Packit Service d3d246
      g_variant_unref (g_variant_ref_sink (parameters));
Packit Service d3d246
      g_printerr (_("unable to connect to D-Bus: %s\n"), error->message);
Packit Service d3d246
      g_error_free (error);
Packit Service d3d246
      return 1;
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  object_path = app_path_for_id (app_id);
Packit Service d3d246
Packit Service d3d246
  result = g_dbus_connection_call_sync (session, app_id, object_path, "org.freedesktop.Application",
Packit Service d3d246
                                        method_name, parameters, G_VARIANT_TYPE_UNIT,
Packit Service d3d246
                                        G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
Packit Service d3d246
Packit Service d3d246
  g_free (object_path);
Packit Service d3d246
Packit Service d3d246
  if (result)
Packit Service d3d246
    {
Packit Service d3d246
      g_variant_unref (result);
Packit Service d3d246
      return 0;
Packit Service d3d246
    }
Packit Service d3d246
  else
Packit Service d3d246
    {
Packit Service d3d246
      g_printerr (_("error sending %s message to application: %s\n"), method_name, error->message);
Packit Service d3d246
      g_error_free (error);
Packit Service d3d246
      return 1;
Packit Service d3d246
    }
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static GVariant *
Packit Service d3d246
app_get_platform_data (void)
Packit Service d3d246
{
Packit Service d3d246
  GVariantBuilder builder;
Packit Service d3d246
  const gchar *startup_id;
Packit Service d3d246
Packit Service d3d246
  g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
Packit Service d3d246
Packit Service d3d246
  if ((startup_id = g_getenv ("DESKTOP_STARTUP_ID")))
Packit Service d3d246
    g_variant_builder_add (&builder, "{sv}", "desktop-startup-id", g_variant_new_string (startup_id));
Packit Service d3d246
Packit Service d3d246
  return g_variant_builder_end (&builder);
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_action (gchar **args)
Packit Service d3d246
{
Packit Service d3d246
  GVariantBuilder params;
Packit Service d3d246
  const gchar *name;
Packit Service d3d246
Packit Service d3d246
  if (!app_check_name (args, "action"))
Packit Service d3d246
    return 1;
Packit Service d3d246
Packit Service d3d246
  if (args[1] == NULL)
Packit Service d3d246
    {
Packit Service d3d246
      g_printerr (_("action name must be given after application id\n"));
Packit Service d3d246
      return 1;
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  name = args[1];
Packit Service d3d246
Packit Service d3d246
  if (!g_action_name_is_valid (name))
Packit Service d3d246
    {
Packit Service d3d246
      g_printerr (_("invalid action name: “%s”\n"
Packit Service d3d246
                    "action names must consist of only alphanumerics, “-” and “.”\n"), name);
Packit Service d3d246
      return 1;
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  g_variant_builder_init (&params, G_VARIANT_TYPE ("av"));
Packit Service d3d246
Packit Service d3d246
  if (args[2])
Packit Service d3d246
    {
Packit Service d3d246
      GError *error = NULL;
Packit Service d3d246
      GVariant *parameter;
Packit Service d3d246
Packit Service d3d246
      parameter = g_variant_parse (NULL, args[2], NULL, NULL, &error);
Packit Service d3d246
Packit Service d3d246
      if (!parameter)
Packit Service d3d246
        {
Packit Service d3d246
          gchar *context;
Packit Service d3d246
Packit Service d3d246
          context = g_variant_parse_error_print_context (error, args[2]);
Packit Service d3d246
          g_printerr (_("error parsing action parameter: %s\n"), context);
Packit Service d3d246
          g_variant_builder_clear (&params);
Packit Service d3d246
          g_error_free (error);
Packit Service d3d246
          g_free (context);
Packit Service d3d246
          return 1;
Packit Service d3d246
        }
Packit Service d3d246
Packit Service d3d246
      g_variant_builder_add (&params, "v", parameter);
Packit Service d3d246
      g_variant_unref (parameter);
Packit Service d3d246
Packit Service d3d246
      if (args[3])
Packit Service d3d246
        {
Packit Service d3d246
          g_printerr (_("actions accept a maximum of one parameter\n"));
Packit Service d3d246
          g_variant_builder_clear (&params);
Packit Service d3d246
          return 1;
Packit Service d3d246
        }
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  return app_call (args[0], "ActivateAction", g_variant_new ("(sav@a{sv})", name, &params, app_get_platform_data ()));
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_activate (const gchar *app_id)
Packit Service d3d246
{
Packit Service d3d246
  return app_call (app_id, "Activate", g_variant_new ("(@a{sv})", app_get_platform_data ()));
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_launch (gchar **args)
Packit Service d3d246
{
Packit Service d3d246
  GVariantBuilder files;
Packit Service d3d246
  gint i;
Packit Service d3d246
Packit Service d3d246
  if (!app_check_name (args, "launch"))
Packit Service d3d246
    return 1;
Packit Service d3d246
Packit Service d3d246
  if (args[1] == NULL)
Packit Service d3d246
    return app_activate (args[0]);
Packit Service d3d246
Packit Service d3d246
  g_variant_builder_init (&files, G_VARIANT_TYPE_STRING_ARRAY);
Packit Service d3d246
Packit Service d3d246
  for (i = 1; args[i]; i++)
Packit Service d3d246
    {
Packit Service d3d246
      GFile *file;
Packit Service d3d246
Packit Service d3d246
      /* "This operation never fails" */
Packit Service d3d246
      file = g_file_new_for_commandline_arg (args[i]);
Packit Service d3d246
      g_variant_builder_add_value (&files, g_variant_new_take_string (g_file_get_uri (file)));
Packit Service d3d246
      g_object_unref (file);
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  return app_call (args[0], "Open", g_variant_new ("(as@a{sv})", &files, app_get_platform_data ()));
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static int
Packit Service d3d246
app_list_actions (gchar **args)
Packit Service d3d246
{
Packit Service d3d246
  const gchar * const *actions;
Packit Service d3d246
  GDesktopAppInfo *app_info;
Packit Service d3d246
  gchar *filename;
Packit Service d3d246
  gint i;
Packit Service d3d246
Packit Service d3d246
  if (!app_check_name (args, "list-actions"))
Packit Service d3d246
    return 1;
Packit Service d3d246
Packit Service d3d246
  if (args[1])
Packit Service d3d246
    {
Packit Service d3d246
      g_printerr (_("list-actions command takes only the application id"));
Packit Service d3d246
      app_help (FALSE, "list-actions");
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  filename = g_strconcat (args[0], ".desktop", NULL);
Packit Service d3d246
  app_info = g_desktop_app_info_new (filename);
Packit Service d3d246
  g_free (filename);
Packit Service d3d246
Packit Service d3d246
  if (app_info == NULL)
Packit Service d3d246
    {
Packit Service d3d246
      g_printerr (_("unable to find desktop file for application %s\n"), args[0]);
Packit Service d3d246
      return 1;
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  actions = g_desktop_app_info_list_actions (app_info);
Packit Service d3d246
Packit Service d3d246
  for (i = 0; actions[i]; i++)
Packit Service d3d246
    g_print ("%s\n", actions[i]);
Packit Service d3d246
Packit Service d3d246
  g_object_unref (app_info);
Packit Service d3d246
Packit Service d3d246
  return 0;
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
int
Packit Service d3d246
main (int argc, char **argv)
Packit Service d3d246
{
Packit Service d3d246
  setlocale (LC_ALL, "");
Packit Service d3d246
  textdomain (GETTEXT_PACKAGE);
Packit Service d3d246
  bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
Packit Service d3d246
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
Packit Service d3d246
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Packit Service d3d246
#endif
Packit Service d3d246
Packit Service d3d246
  if (argc < 2)
Packit Service d3d246
    return app_help (TRUE, NULL);
Packit Service d3d246
Packit Service d3d246
  if (g_str_equal (argv[1], "help"))
Packit Service d3d246
    return app_help (TRUE, argv[2]);
Packit Service d3d246
Packit Service d3d246
  if (g_str_equal (argv[1], "version"))
Packit Service d3d246
    return app_version (argv + 2);
Packit Service d3d246
Packit Service d3d246
  if (g_str_equal (argv[1], "list-apps"))
Packit Service d3d246
    return app_list (argv + 2);
Packit Service d3d246
Packit Service d3d246
  if (g_str_equal (argv[1], "launch"))
Packit Service d3d246
    return app_launch (argv + 2);
Packit Service d3d246
Packit Service d3d246
  if (g_str_equal (argv[1], "action"))
Packit Service d3d246
    return app_action (argv + 2);
Packit Service d3d246
Packit Service d3d246
  if (g_str_equal (argv[1], "list-actions"))
Packit Service d3d246
    return app_list_actions (argv + 2);
Packit Service d3d246
Packit Service d3d246
  g_printerr (_("unrecognised command: %s\n\n"), argv[1]);
Packit Service d3d246
Packit Service d3d246
  return app_help (FALSE, NULL);
Packit Service d3d246
}