[glib] New gapplication(1) tool
- From: Ryan Lortie <desrt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] New gapplication(1) tool
- Date: Thu, 17 Oct 2013 14:12:38 +0000 (UTC)
commit 9defb6b1b1de18b6005148e036941e89b400dbd2
Author: Ryan Lortie <desrt desrt ca>
Date: Sun Jul 14 19:43:19 2013 -0400
New gapplication(1) tool
This is essentially a commandline implementation of the client-side of
the org.freedesktop.Application D-Bus interface.
It includes support for tab-completion based on desktop files and their
contents.
https://bugzilla.gnome.org/show_bug.cgi?id=704218
docs/reference/gio/Makefile.am | 1 +
docs/reference/gio/gapplication.xml | 352 ++++++++++++++++++++++++++
gio/.gitignore | 1 +
gio/Makefile.am | 9 +
gio/completion/gapplication | 55 ++++
gio/gapplication-tool.c | 463 +++++++++++++++++++++++++++++++++++
6 files changed, 881 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gio/Makefile.am b/docs/reference/gio/Makefile.am
index 112626b..42907ca 100644
--- a/docs/reference/gio/Makefile.am
+++ b/docs/reference/gio/Makefile.am
@@ -146,6 +146,7 @@ man_MANS =
if ENABLE_MAN
man_MANS += \
+ gapplication.1 \
gio-querymodules.1 \
glib-compile-schemas.1 \
glib-compile-resources.1 \
diff --git a/docs/reference/gio/gapplication.xml b/docs/reference/gio/gapplication.xml
new file mode 100644
index 0000000..13e3f23
--- /dev/null
+++ b/docs/reference/gio/gapplication.xml
@@ -0,0 +1,352 @@
+<refentry id="gapplication-tool" lang="en">
+ <refentryinfo>
+ <title>gapplication</title>
+ <productname>GIO</productname>
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Ryan</firstname>
+ <surname>Lortie</surname>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>gapplication</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>gapplication</refname>
+ <refpurpose>D-Bus application launcher</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>gapplication</command>
+ <arg choice="plain">help</arg>
+ <arg choice="opt"><replaceable>COMMAND</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>gapplication</command>
+ <arg choice="plain">version</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>gapplication</command>
+ <arg choice="plain">list-apps</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>gapplication</command>
+ <arg choice="plain">launch</arg>
+ <arg choice="plain"><replaceable>APPID</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>gapplication</command>
+ <arg choice="plain">launch</arg>
+ <arg choice="plain"><replaceable>APPID</replaceable></arg>
+ <arg choice="opt" rep="repeat"><replaceable>FILE</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>gapplication</command>
+ <arg choice="plain">list-actions</arg>
+ <arg choice="plain"><replaceable>APPID</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>gapplication</command>
+ <arg choice="plain">action</arg>
+ <arg choice="plain"><replaceable>APPID</replaceable></arg>
+ <arg choice="plain"><replaceable>ACTION</replaceable></arg>
+ <arg choice="opt"><replaceable>PARAMETER</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>gapplication</command> is a commandline implementation of the client-side of the
+ <interfacename>org.freedesktop.Application</interfacename> interface as specified by the
freedesktop.org
+ Desktop Entry Specification.
+ </para>
+
+ <para>
+ <command>gapplication</command> can be used to start applications that have
+ <varname>DBusActivatable</varname> set to <literal>true</literal> in their
<filename>.desktop</filename>
+ files and can be used to send messages to already-running instances of other applications.
+ </para>
+
+ <para>
+ It is possible for applications to refer to <command>gapplication</command> in the
<varname>Exec</varname>
+ line of their <filename class='extension'>.desktop</filename> file to maintain backwards compatibility
+ with implementations that do not directly support <varname>DBusActivatable</varname>.
+ </para>
+
+ <para>
+ <command>gapplication</command> ships as part of <application>GLib</application>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Commands</title>
+
+ <refsect2>
+ <title>Global commands</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>
+ <command>help</command>
+ <arg choice="opt"><replaceable>COMMAND</replaceable></arg>
+ </term>
+ <listitem>
+ <para>
+ Displays a short synopsis of the available commands or provides detailed help on a specific
+ command.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>version</command>
+ </term>
+ <listitem>
+ <para>
+ Prints the GLib version whence <command>gapplication</command> came.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>list-apps</command>
+ </term>
+ <listitem>
+ <para>
+ Prints a list of all application IDs that are known to support D-Bus activation. This list is
+ generated by scanning <filename class='extension'>.desktop</filename> files as per the current
+ <envar>XDG_DATA_DIRS</envar>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>launch</command>
+ <arg choice="plain"><replaceable>APPID</replaceable></arg>
+ <arg choice="opt" rep="repeat"><replaceable>FILE</replaceable></arg>
+ </term>
+ <listitem>
+ <para>
+ Launches an application.
+ </para>
+ <para>
+ The first parameter is the application ID in the familiar "reverse DNS" style (eg:
+ '<literal>org.gnome.app</literal>') without the <filename class='extension'>.desktop</filename>
+ suffix.
+ </para>
+ <para>
+ Optionally, if additional parameters are given, they are treated as the names of files to open
and
+ may be filenames or URIs. If no files are given then the application is simply activated.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>list-actions</command>
+ <arg choice="plain"><replaceable>APPID</replaceable></arg>
+ </term>
+ <listitem>
+ <para>
+ List the actions declared in the application's <filename class='extension'>.desktop</filename>
+ file. The parameter is the application ID, as above.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>action</command>
+ <arg choice="plain"><replaceable>APPID</replaceable></arg>
+ <arg choice="plain"><replaceable>ACTION</replaceable></arg>
+ <arg choice="opt"><replaceable>PARAMETER</replaceable></arg>
+ </term>
+ <listitem>
+ <para>
+ Invokes the named action (in the same way as would occur when activating an action specified in
+ the <filename class='extension'>.desktop</filename> file).
+ </para>
+ <para>
+ The application ID (as above) is the first parameter. The action name follows.
+ </para>
+ <para>
+ Optionally, following the action name can be one parameter, in GVariant format, given as a
single
+ argument. Make sure to use sufficient quoting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <refsect2>
+ <title>From the commandline</title>
+
+ <para>
+ Launching an application:
+ </para>
+
+ <programlisting>
+ gapplication launch org.example.fooview
+ </programlisting>
+
+ <para>
+ Opening a file with an application:
+ </para>
+
+ <programlisting>
+ gapplication launch org.example.fooview ~/file.foo
+ </programlisting>
+
+ <para>
+ Opening many files with an application:
+ </para>
+
+ <programlisting>
+ gapplication launch org.example.fooview ~/foos/*.foo
+ </programlisting>
+
+ <para>
+ Invoking an action on an application:
+ </para>
+
+ <programlisting>
+ gapplication action org.example.fooview create
+ </programlisting>
+
+ <para>
+ Invoking an action on an application, with an action:
+ </para>
+
+ <programlisting>
+ gapplication action org.example.fooview show-item '"item_id_828739"'
+ </programlisting>
+ </refsect2>
+
+ <refsect2>
+ <title>
+ From the <varname>Exec</varname> lines of a <filename class='extension'>.desktop</filename> file
+ </title>
+
+ <para>
+ The commandline interface of <command>gapplication</command> was designed so that it could be used
+ directly from the <varname>Exec</varname> line of a <filename class='extension'>.desktop</filename>
+ file.
+ </para>
+
+ <para>
+ You might want to do this to allow for backwards compatibility with implementations of the
specification
+ that do not understand how to do D-Bus activation, without having to install a separate utility
program.
+ </para>
+
+ <para>
+ Consider the following example:
+ </para>
+
+ <programlisting>
+ [Desktop Entry]
+ Version=1.1
+ Type=Application
+ Name=Foo Viewer
+ DBusActivatable=true
+ MimeType=image/x-foo;
+ Exec=gapplication launch org.example.fooview %F
+ Actions=gallery;create;
+
+ [Desktop Action gallery]
+ Name=Browse Gallery
+ Exec=gapplication action org.example.fooview gallery
+
+ [Desktop Action create]
+ Name=Create a new Foo!
+ Exec=gapplication action org.example.fooview create
+ </programlisting>
+ </refsect2>
+
+ <refsect2>
+ <title>From a script</title>
+
+ <para>
+ If installing an application that supports D-Bus activation you may still want to put a file in
+ <filename class='directory'>/usr/bin</filename> so that your program can be started from a terminal.
+ </para>
+
+ <para>
+ It is possible for this file to be a shell script. The script can handle arguments such as --help
and
+ --version directly. It can also parse other command line arguments and convert them to uses of
+ <command>gapplication</command> to activate the application, open files, or invoke actions.
+ </para>
+
+ <para>
+ Here is a simplified example, as may be installed in <filename>/usr/bin/fooview</filename>:
+ </para>
+
+ <programlisting>
+ #!/bin/sh
+
+ case "$1" in
+ --help)
+ echo "see 'man fooview' for more information"
+ ;;
+
+ --version)
+ echo "fooview 1.2"
+ ;;
+
+ --gallery)
+ gapplication action org.example.fooview gallery
+ ;;
+
+ --create)
+ gapplication action org.example.fooview create
+ ;;
+
+ -*)
+ echo "unrecognised commandline argument"
+ exit 1
+ ;;
+
+ *)
+ gapplication launch org.example.fooview "$@"
+ ;;
+ esac
+ </programlisting>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>See also</title>
+ <para>
+ <ulink url='http://standards.freedesktop.org/desktop-entry-spec/latest/'>Desktop Entry
Specification</ulink>,
+ <citerefentry>
+ <refentrytitle>gdbus</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>xdg-open</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>desktop-file-validate</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/gio/.gitignore b/gio/.gitignore
index be25b26..5aa5588 100644
--- a/gio/.gitignore
+++ b/gio/.gitignore
@@ -14,3 +14,4 @@ gnetworking.h
gresource
gschema-compile
gsettings
+gapplication
diff --git a/gio/Makefile.am b/gio/Makefile.am
index ba596e5..7d24966 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -720,8 +720,17 @@ gdbus_LDADD = libgio-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(top_builddir)/gobject/libgobject-2.0.la
+# ------------------------------------------------------------------------
+# gapplication(1) tool
+bin_PROGRAMS += gapplication
+gapplication_SOURCES = gapplication-tool.c
+gapplication_LDADD = libgio-2.0.la \
+ $(top_builddir)/glib/libglib-2.0.la \
+ $(top_builddir)/gobject/libgobject-2.0.la
+
completiondir = $(datadir)/bash-completion/completions
completion_DATA = \
+ completion/gapplication \
completion/gdbus \
completion/gsettings \
completion/gresource
diff --git a/gio/completion/gapplication b/gio/completion/gapplication
new file mode 100644
index 0000000..565025b
--- /dev/null
+++ b/gio/completion/gapplication
@@ -0,0 +1,55 @@
+
+# Check for bash
+[ -z "$BASH_VERSION" ] && return
+
+####################################################################################################
+
+__app() {
+ case "${COMP_CWORD}" in
+ 1)
+ COMPREPLY=($(compgen -W "help version list-apps launch action list-actions" -- "${COMP_WORDS[1]}"))
+ return 0
+ ;;
+
+ 2)
+ case "${COMP_WORDS[1]}" in
+ launch|action|list-actions)
+ COMPREPLY=($(compgen -W "`gapplication list-apps`" -- "${COMP_WORDS[2]}"))
+ return 0
+ ;;
+
+ *)
+ COMPREPLY=()
+ return 0
+ ;;
+ esac
+ ;;
+ esac
+
+ # Otherwise, what we will do is based on the command in ${COMP_WORDS[1]}
+ case "${COMP_WORDS[1]}" in
+ action)
+ # Word 3 is the action name. This is the only one we can help with.
+ if [ "${COMP_CWORD}" == 3 ]; then
+ COMPREPLY=($(compgen -W "`gapplication list-actions "${COMP_WORDS[2]}"`" -- "${COMP_WORDS[3]}"))
+ return 0
+ else
+ COMPREPLY=()
+ return 0
+ fi
+ ;;
+ launch)
+ # Filenames...
+ COMPREPLY=($(compgen -A file "${COMP_WORDS[COMP_CWORD]}"))
+ return 0
+ ;;
+ *)
+ # Nothing else should be out this far...
+ COMPREPLY=()
+ return 0
+ esac
+}
+
+####################################################################################################
+
+complete -F __app gapplication
diff --git a/gio/gapplication-tool.c b/gio/gapplication-tool.c
new file mode 100644
index 0000000..c152909
--- /dev/null
+++ b/gio/gapplication-tool.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright © 2013 Canonical Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include <gio/gdesktopappinfo.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <string.h>
+#include <locale.h>
+
+struct help_topic
+{
+ const gchar *command;
+ const gchar *summary;
+ const gchar *description;
+ const gchar *synopsis;
+};
+
+struct help_substvar
+{
+ const gchar *var;
+ const gchar *description;
+};
+
+static const struct help_topic topics[] = {
+ { "help", N_("Print help"),
+ N_("Print help"),
+ N_("[COMMAND]")
+ },
+ { "version", N_("Print version"),
+ N_("Print version information and exit")
+ },
+ { "list-apps", N_("List applications"),
+ N_("List the installed D-Bus activatable applications (by .desktop files)")
+ },
+ { "launch", N_("Launch an application"),
+ N_("Launch the application (with optional files to open)"),
+ N_("APPID [FILE...]")
+ },
+ { "action", N_("Activate an action"),
+ N_("Invoke an action on the application"),
+ N_("APPID ACTION [PARAMETER]")
+ },
+ { "list-actions", N_("List available actions"),
+ N_("List static actions for an application (from .desktop file)"),
+ N_("APPID")
+ }
+};
+
+static const struct help_substvar substvars[] = {
+ { N_("COMMAND"), N_("The command to print detailed help for") },
+ { N_("APPID"), N_("Application identifier in D-Bus format (eg: org.example.viewer)") },
+ { N_("FILE"), N_("Optional relative or relative filenames, or URIs to open") },
+ { N_("ACTION"), N_("The action name to invoke") },
+ { N_("PARAMETER"), N_("Optional parameter to the action invocation, in GVariant format") }
+};
+
+static int
+app_help (gboolean requested,
+ const gchar *command)
+{
+ const struct help_topic *topic = NULL;
+ GString *string;
+
+ string = g_string_new (NULL);
+
+ if (command)
+ {
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (topics); i++)
+ if (g_str_equal (topics[i].command, command))
+ topic = &topics[i];
+
+ if (!topic)
+ {
+ g_string_printf (string, _("Unknown command %s\n\n"), command);
+ requested = FALSE;
+ }
+ }
+
+ g_string_append (string, _("Usage:\n"));
+
+ if (topic)
+ {
+ gint maxwidth;
+ gint i;
+
+ g_string_append_printf (string, "\n %s %s %s\n\n", "gapplication",
+ topic->command, topic->synopsis ? _(topic->synopsis) : "");
+ g_string_append_printf (string, "%s\n\n", _(topic->description));
+
+ if (topic->synopsis)
+ {
+ g_string_append (string, _("Arguments:\n"));
+
+ maxwidth = 0;
+ for (i = 0; i < G_N_ELEMENTS (substvars); i++)
+ if (strstr (topic->synopsis, substvars[i].var))
+ maxwidth = MAX(maxwidth, strlen (_(substvars[i].var)));
+
+ for (i = 0; i < G_N_ELEMENTS (substvars); i++)
+ if (strstr (topic->synopsis, substvars[i].var))
+ g_string_append_printf (string, " %-*.*s %s\n", maxwidth, maxwidth,
+ _(substvars[i].var), _(substvars[i].description));
+ g_string_append (string, "\n");
+ }
+ }
+ else
+ {
+ gint maxwidth;
+ gint i;
+
+ g_string_append_printf (string, "\n %s %s %s\n\n", "gapplication", _("COMMAND"), _("[ARGS...]"));
+ g_string_append_printf (string, _("Commands:\n"));
+
+ maxwidth = 0;
+ for (i = 0; i < G_N_ELEMENTS (topics); i++)
+ maxwidth = MAX(maxwidth, strlen (topics[i].command));
+
+ for (i = 0; i < G_N_ELEMENTS (topics); i++)
+ g_string_append_printf (string, " %-*.*s %s\n", maxwidth, maxwidth,
+ topics[i].command, _(topics[i].summary));
+
+ g_string_append (string, "\n");
+ /* Translators: do not translate 'help', but please translate 'COMMAND'. */
+ g_string_append_printf (string, _("Use '%s help COMMAND' to get detailed help.\n\n"), "gapplication");
+ }
+
+ if (requested)
+ g_print ("%s", string->str);
+ else
+ g_printerr ("%s\n", string->str);
+
+ g_string_free (string, TRUE);
+
+ return requested ? 0 : 1;
+}
+
+static gboolean
+app_check_name (gchar **args,
+ const gchar *command)
+{
+ if (args[0] == NULL)
+ {
+ g_printerr (_("%s command requires an application id to directly follow\n\n"), command);
+ return FALSE;
+ }
+
+ if (!g_dbus_is_name (args[0]))
+ {
+ g_printerr (_("invalid application id: '%s'\n"), args[0]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+app_no_args (const gchar *command)
+{
+ /* Translators: %s is replaced with a command name like 'list-actions' */
+ g_printerr (_("'%s' takes no arguments\n\n"), command);
+ return app_help (FALSE, command);
+}
+
+static int
+app_version (gchar **args)
+{
+ if (g_strv_length (args))
+ return app_no_args ("version");
+
+ g_print (PACKAGE_VERSION "\n");
+ return 0;
+}
+
+static int
+app_list (gchar **args)
+{
+ GList *apps;
+
+ if (g_strv_length (args))
+ return app_no_args ("list");
+
+ apps = g_app_info_get_all ();
+
+ while (apps)
+ {
+ GDesktopAppInfo *info = apps->data;
+
+ if (G_IS_DESKTOP_APP_INFO (info))
+ if (g_desktop_app_info_get_boolean (info, "DBusActivatable"))
+ {
+ const gchar *filename;
+
+ filename = g_app_info_get_id (G_APP_INFO (info));
+ if (g_str_has_suffix (filename, ".desktop"))
+ {
+ gchar *id;
+
+ id = g_strndup (filename, strlen (filename) - 8);
+ g_print ("%s\n", id);
+ g_free (id);
+ }
+ }
+
+ apps = g_list_delete_link (apps, apps);
+ g_object_unref (info);
+ }
+
+ return 0;
+}
+
+static gchar *
+app_path_for_id (const gchar *app_id)
+{
+ gchar *path;
+ gint i;
+
+ path = g_strconcat ("/", app_id, NULL);
+ for (i = 0; path[i]; i++)
+ if (path[i] == '.')
+ path[i] = '/';
+
+ return path;
+}
+
+static int
+app_call (const gchar *app_id,
+ const gchar *method_name,
+ GVariant *parameters)
+{
+ GDBusConnection *session;
+ GError *error = NULL;
+ gchar *object_path;
+ GVariant *result;
+
+
+ session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ if (!session)
+ {
+ g_variant_unref (g_variant_ref_sink (parameters));
+ g_printerr (_("unable to connect to D-Bus: %s\n"), error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ object_path = app_path_for_id (app_id);
+
+ result = g_dbus_connection_call_sync (session, app_id, object_path, "org.freedesktop.Application",
+ method_name, parameters, G_VARIANT_TYPE_UNIT,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+
+ g_free (object_path);
+
+ if (result)
+ {
+ g_variant_unref (result);
+ return 0;
+ }
+ else
+ {
+ g_printerr (_("error sending %s message to application: %s\n"), method_name, error->message);
+ g_error_free (error);
+ return 1;
+ }
+}
+
+static GVariant *
+app_get_platform_data (void)
+{
+ GVariantBuilder builder;
+ const gchar *startup_id;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+
+ if ((startup_id = g_getenv ("DESKTOP_STARTUP_iD")))
+ g_variant_builder_add (&builder, "{sv}", "desktop-startup-id", g_variant_new_string (startup_id));
+
+ return g_variant_builder_end (&builder);
+}
+
+static int
+app_action (gchar **args)
+{
+ GVariantBuilder params;
+ const gchar *name;
+
+ if (!app_check_name (args, "action"))
+ return 1;
+
+ if (args[1] == NULL)
+ {
+ g_printerr (_("action name must be given after application id\n"));
+ return 1;
+ }
+
+ name = args[1];
+
+ if (!g_action_name_is_valid (name))
+ {
+ g_printerr (_("invalid action name: '%s'\n"
+ "action names must consist of only alphanumerics, '-' and '.'\n"), name);
+ return 1;
+ }
+
+ g_variant_builder_init (¶ms, G_VARIANT_TYPE ("av"));
+
+ if (args[2])
+ {
+ GError *error = NULL;
+ GVariant *parameter;
+
+ parameter = g_variant_parse (NULL, args[2], NULL, NULL, &error);
+
+ if (!parameter)
+ {
+ g_printerr (_("error parsing action parameter: %s\n"), error->message);
+ g_variant_builder_clear (¶ms);
+ g_error_free (error);
+ return 1;
+ }
+
+ g_variant_builder_add (¶ms, "v", parameter);
+ g_variant_unref (parameter);
+
+ if (args[3])
+ {
+ g_printerr (_("actions accept a maximum of one parameter\n"));
+ g_variant_builder_clear (¶ms);
+ return 1;
+ }
+ }
+
+ return app_call (args[0], "ActivateAction", g_variant_new ("(sav a{sv})", name, ¶ms,
app_get_platform_data ()));
+}
+
+static int
+app_activate (const gchar *app_id)
+{
+ return app_call (app_id, "Activate", g_variant_new ("(@a{sv})", app_get_platform_data ()));
+}
+
+static int
+app_launch (gchar **args)
+{
+ GVariantBuilder files;
+ gint i;
+
+ if (!app_check_name (args, "launch"))
+ return 1;
+
+ if (args[1] == NULL)
+ return app_activate (args[0]);
+
+ g_variant_builder_init (&files, G_VARIANT_TYPE_STRING_ARRAY);
+
+ for (i = 1; args[i]; i++)
+ {
+ GFile *file;
+
+ /* "This operation never fails" */
+ file = g_file_new_for_commandline_arg (args[i]);
+ g_variant_builder_add_value (&files, g_variant_new_take_string (g_file_get_uri (file)));
+ g_object_unref (file);
+ }
+
+ return app_call (args[0], "Open", g_variant_new ("(as a{sv})", &files, app_get_platform_data ()));
+}
+
+static int
+app_list_actions (gchar **args)
+{
+ const gchar * const *actions;
+ GDesktopAppInfo *app_info;
+ gchar *filename;
+ gint i;
+
+ if (!app_check_name (args, "list-actions"))
+ return 1;
+
+ if (args[1])
+ {
+ g_printerr (_("list-actions command takes only the application id"));
+ app_help (FALSE, "list-actions");
+ }
+
+ filename = g_strconcat (args[0], ".desktop", NULL);
+ app_info = g_desktop_app_info_new (filename);
+ g_free (filename);
+
+ if (app_info == NULL)
+ {
+ g_printerr (_("unable to find desktop file for application %s\n"), args[0]);
+ return 1;
+ }
+
+ actions = g_desktop_app_info_list_actions (app_info);
+
+ for (i = 0; actions[i]; i++)
+ g_print ("%s\n", actions[i]);
+
+ g_object_unref (app_info);
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ setlocale (LC_ALL, "");
+ textdomain (GETTEXT_PACKAGE);
+ bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+ if (argc < 2)
+ return app_help (TRUE, NULL);
+
+ if (g_str_equal (argv[1], "help"))
+ return app_help (TRUE, argv[2]);
+
+ if (g_str_equal (argv[1], "version"))
+ return app_version (argv + 2);
+
+ if (g_str_equal (argv[1], "list-apps"))
+ return app_list (argv + 2);
+
+ if (g_str_equal (argv[1], "launch"))
+ return app_launch (argv + 2);
+
+ if (g_str_equal (argv[1], "action"))
+ return app_action (argv + 2);
+
+ if (g_str_equal (argv[1], "list-actions"))
+ return app_list_actions (argv + 2);
+
+ g_printerr (_("unrecognised command: %s\n\n"), argv[1]);
+
+ return app_help (FALSE, NULL);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]