mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-07-31 22:23:39 +02:00
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
This commit is contained in:
@@ -146,6 +146,7 @@ man_MANS =
|
||||
if ENABLE_MAN
|
||||
|
||||
man_MANS += \
|
||||
gapplication.1 \
|
||||
gio-querymodules.1 \
|
||||
glib-compile-schemas.1 \
|
||||
glib-compile-resources.1 \
|
||||
|
352
docs/reference/gio/gapplication.xml
Normal file
352
docs/reference/gio/gapplication.xml
Normal file
@@ -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>
|
1
gio/.gitignore
vendored
1
gio/.gitignore
vendored
@@ -14,3 +14,4 @@ gnetworking.h
|
||||
gresource
|
||||
gschema-compile
|
||||
gsettings
|
||||
gapplication
|
||||
|
@@ -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
|
||||
|
55
gio/completion/gapplication
Normal file
55
gio/completion/gapplication
Normal file
@@ -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
|
463
gio/gapplication-tool.c
Normal file
463
gio/gapplication-tool.c
Normal file
@@ -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);
|
||||
}
|
Reference in New Issue
Block a user