2 * Copyright © 2010 Codethink Limited
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * licence or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful, but
10 * 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, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
19 * Authors: Ryan Lortie <desrt@desrt.ca>
24 #include "gapplicationcommandline.h"
31 G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
34 * SECTION:gapplicationcommandline
35 * @title: GApplicationCommandLine
36 * @short_description: A command-line invocation of an application
37 * @see_also: #GApplication
39 * #GApplicationCommandLine represents a command-line invocation of
40 * an application. It is created by #GApplication and emitted
41 * in the #GApplication::command-line signal and virtual function.
43 * The class contains the list of arguments that the program was invoked
44 * with. It is also possible to query if the commandline invocation was
45 * local (ie: the current process is running in direct response to the
46 * invocation) or remote (ie: some other process forwarded the
47 * commandline to this process).
49 * The GApplicationCommandLine object can provide the @argc and @argv
50 * parameters for use with the #GOptionContext command-line parsing API,
51 * with the g_application_command_line_get_arguments() function. See
52 * <xref linkend="gapplication-example-cmdline3"> for an example.
54 * The exit status of the originally-invoked process may be set and
55 * messages can be printed to stdout or stderr of that process. The
56 * lifecycle of the originally-invoked process is tied to the lifecycle
57 * of this object (ie: the process exits when the last reference is
60 * The main use for #GApplicationCommandline (and the
61 * #GApplication::command-line signal) is 'Emacs server' like use cases:
62 * You can set the <envvar>EDITOR</envvar> environment variable to have
63 * e.g. git use your favourite editor to edit commit messages, and if you
64 * already have an instance of the editor running, the editing will happen
65 * in the running instance, instead of opening a new one. An important
66 * aspect of this use case is that the process that gets started by git
67 * does not return until the editing is done.
69 * <example id="gapplication-example-cmdline"><title>Handling commandline arguments with GApplication</title>
71 * A simple example where the commandline is completely handled
72 * in the ::command-line handler. The calling process exits once the
73 * signal handler in the main instance has returned, and the return
74 * value of the signal handler becomes the exit status of the calling
78 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline.c">
79 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
84 * <example id="gapplication-example-cmdline2"><title>Split commandline handling</title>
86 * An example of split commandline handling. Options that start with
87 * <literal>--local-</literal> are handled locally, all other options are
88 * passed to the ::command-line handler which runs in the main instance.
91 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline2.c">
92 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
97 * <example id="gapplication-example-cmdline3"><title>Deferred commandline handling</title>
99 * An example of deferred commandline handling. Here, the commandline is
100 * not completely handled in the ::command-line handler. Instead, we keep
101 * a reference to the GApplicationCommandline object and handle it later
102 * (in this example, in an idle). Note that it is necessary to hold the
103 * application until you are done with the commandline.
106 * This example also shows how to use #GOptionContext for parsing the
107 * commandline arguments.
110 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline3.c">
111 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
125 struct _GApplicationCommandLinePrivate
127 GVariant *platform_data;
131 const gchar **environ;
135 /* All subclasses represent remote invocations of some kind. */
136 #define IS_REMOTE(cmdline) (G_TYPE_FROM_INSTANCE (cmdline) != \
137 G_TYPE_APPLICATION_COMMAND_LINE)
140 grok_platform_data (GApplicationCommandLine *cmdline)
146 g_variant_iter_init (&iter, cmdline->priv->platform_data);
148 while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
149 if (strcmp (key, "cwd") == 0)
151 if (!cmdline->priv->cwd)
152 cmdline->priv->cwd = g_variant_ref (value);
155 else if (strcmp (key, "environ") == 0)
157 if (!cmdline->priv->environ)
158 cmdline->priv->environ =
159 g_variant_get_bytestring_array (value, NULL);
164 g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
165 const gchar *message)
167 g_print ("%s\n", message);
171 g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
172 const gchar *message)
174 g_printerr ("%s\n", message);
178 g_application_command_line_get_property (GObject *object,
183 GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
188 g_value_set_variant (value, cmdline->priv->arguments);
191 case PROP_PLATFORM_DATA:
192 g_value_set_variant (value, cmdline->priv->platform_data);
196 g_value_set_boolean (value, IS_REMOTE (cmdline));
200 g_assert_not_reached ();
205 g_application_command_line_set_property (GObject *object,
210 GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
215 g_assert (cmdline->priv->arguments == NULL);
216 cmdline->priv->arguments = g_value_dup_variant (value);
219 case PROP_PLATFORM_DATA:
220 g_assert (cmdline->priv->platform_data == NULL);
221 cmdline->priv->platform_data = g_value_dup_variant (value);
222 if (cmdline->priv->platform_data != NULL)
223 grok_platform_data (cmdline);
227 g_assert_not_reached ();
232 g_application_command_line_finalize (GObject *object)
234 GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
236 if (cmdline->priv->platform_data)
237 g_variant_unref (cmdline->priv->platform_data);
238 if (cmdline->priv->arguments)
239 g_variant_unref (cmdline->priv->arguments);
240 if (cmdline->priv->cwd)
241 g_variant_unref (cmdline->priv->cwd);
243 G_OBJECT_CLASS (g_application_command_line_parent_class)
248 g_application_command_line_init (GApplicationCommandLine *cmdline)
251 G_TYPE_INSTANCE_GET_PRIVATE (cmdline,
252 G_TYPE_APPLICATION_COMMAND_LINE,
253 GApplicationCommandLinePrivate);
257 g_application_command_line_class_init (GApplicationCommandLineClass *class)
259 GObjectClass *object_class = G_OBJECT_CLASS (class);
261 object_class->get_property = g_application_command_line_get_property;
262 object_class->set_property = g_application_command_line_set_property;
263 object_class->finalize = g_application_command_line_finalize;
264 class->printerr_literal = g_application_command_line_real_printerr_literal;
265 class->print_literal = g_application_command_line_real_print_literal;
267 g_object_class_install_property (object_class, PROP_ARGUMENTS,
268 g_param_spec_variant ("arguments",
269 P_("Commandline arguments"),
270 P_("The commandline that caused this ::command-line signal emission"),
271 G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
272 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
273 G_PARAM_STATIC_STRINGS));
275 g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
276 g_param_spec_variant ("platform-data",
278 P_("Platform-specific data for the commandline"),
279 G_VARIANT_TYPE ("a{sv}"), NULL,
280 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
281 G_PARAM_STATIC_STRINGS));
283 g_object_class_install_property (object_class, PROP_IS_REMOTE,
284 g_param_spec_boolean ("is-remote",
286 P_("TRUE if this is a remote commandline"),
288 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
290 g_type_class_add_private (class, sizeof (GApplicationCommandLinePrivate));
295 * g_application_command_line_get_arguments:
296 * @cmdline: a #GApplicationCommandLine
297 * @argc: (out): the length of the arguments array, or %NULL
299 * Gets the list of arguments that was passed on the command line.
301 * The strings in the array may contain non-utf8 data.
303 * The return value is %NULL-terminated and should be freed using
306 * Returns: (array length=argc) (transfer full): the string array
307 * containing the arguments (the argv)
312 g_application_command_line_get_arguments (GApplicationCommandLine *cmdline,
318 g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
320 argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
329 * g_application_command_line_get_cwd:
330 * @cmdline: a #GApplicationCommandLine
332 * Gets the working directory of the command line invocation. The
333 * string may contain non-utf8 data.
335 * It is possible that the remote application did not send a working
336 * directory, so this may be %NULL.
338 * The return value should not be modified or freed and is valid for as
339 * long as @cmdline exists.
341 * Returns: the current directory, or %NULL
346 g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
348 if (cmdline->priv->cwd)
349 return g_variant_get_bytestring (cmdline->priv->cwd);
355 * g_application_command_line_get_environ:
356 * @cmdline: a #GApplicationCommandLine
358 * Gets the contents of the 'environ' variable of the command line
359 * invocation, as would be returned by g_get_environ(). The strings may
360 * contain non-utf8 data.
362 * The remote application usually does not send an environment. Use
363 * %G_APPLICATION_SEND_ENVIRONMENT to affect that. Even with this flag
364 * set it is possible that the environment is still not available (due
365 * to invocation messages from other applications).
367 * The return value should not be modified or freed and is valid for as
368 * long as @cmdline exists.
370 * Returns: (array zero-terminated=1) (transfer none): the environment
371 * strings, or %NULL if they were not sent
375 const gchar * const *
376 g_application_command_line_get_environ (GApplicationCommandLine *cmdline)
378 return cmdline->priv->environ;
382 * g_application_command_line_getenv:
383 * @cmdline: a #GApplicationCommandLine
384 * @name: the environment variable to get
386 * Gets the value of a particular environment variable of the command
387 * line invocation, as would be returned by g_getenv(). The strings may
388 * contain non-utf8 data.
390 * The remote application usually does not send an environment. Use
391 * %G_APPLICATION_SEND_ENVIRONMENT to affect that. Even with this flag
392 * set it is possible that the environment is still not available (due
393 * to invocation messages from other applications).
395 * The return value should not be modified or freed and is valid for as
396 * long as @cmdline exists.
398 * Returns: the value of the variable, or %NULL if unset or unsent
403 g_application_command_line_getenv (GApplicationCommandLine *cmdline,
406 gint length = strlen (name);
409 /* TODO: expand on windows */
410 if (cmdline->priv->environ)
411 for (i = 0; cmdline->priv->environ[i]; i++)
412 if (strncmp (cmdline->priv->environ[i], name, length) == 0 &&
413 cmdline->priv->environ[i][length] == '=')
414 return cmdline->priv->environ[i] + length + 1;
420 * g_application_command_line_get_is_remote:
421 * @cmdline: a #GApplicationCommandLine
423 * Determines if @cmdline represents a remote invocation.
425 * Returns: %TRUE if the invocation was remote
430 g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
432 return IS_REMOTE (cmdline);
436 * g_application_command_line_print:
437 * @cmdline: a #GApplicationCommandLine
438 * @format: a printf-style format string
439 * @...: arguments, as per @format
441 * Formats a message and prints it using the stdout print handler in the
444 * If @cmdline is a local invocation then this is exactly equivalent to
445 * g_print(). If @cmdline is remote then this is equivalent to calling
446 * g_print() in the invoking process.
451 g_application_command_line_print (GApplicationCommandLine *cmdline,
458 g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
459 g_return_if_fail (format != NULL);
461 va_start (ap, format);
462 message = g_strdup_vprintf (format, ap);
465 G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
466 ->print_literal (cmdline, message);
471 * g_application_command_line_printerr:
472 * @cmdline: a #GApplicationCommandLine
473 * @format: a printf-style format string
474 * @...: arguments, as per @format
476 * Formats a message and prints it using the stderr print handler in the
479 * If @cmdline is a local invocation then this is exactly equivalent to
480 * g_printerr(). If @cmdline is remote then this is equivalent to
481 * calling g_printerr() in the invoking process.
486 g_application_command_line_printerr (GApplicationCommandLine *cmdline,
493 g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
494 g_return_if_fail (format != NULL);
496 va_start (ap, format);
497 message = g_strdup_vprintf (format, ap);
500 G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
501 ->printerr_literal (cmdline, message);
506 * g_application_command_line_set_exit_status:
507 * @cmdline: a #GApplicationCommandLine
508 * @exit_status: the exit status
510 * Sets the exit status that will be used when the invoking process
513 * The return value of the #GApplication::command-line signal is
514 * passed to this function when the handler returns. This is the usual
515 * way of setting the exit status.
517 * In the event that you want the remote invocation to continue running
518 * and want to decide on the exit status in the future, you can use this
519 * call. For the case of a remote invocation, the remote process will
520 * typically exit when the last reference is dropped on @cmdline. The
521 * exit status of the remote process will be equal to the last value
522 * that was set with this function.
524 * In the case that the commandline invocation is local, the situation
525 * is slightly more complicated. If the commandline invocation results
526 * in the mainloop running (ie: because the use-count of the application
527 * increased to a non-zero value) then the application is considered to
528 * have been 'successful' in a certain sense, and the exit status is
529 * always zero. If the application use count is zero, though, the exit
530 * status of the local #GApplicationCommandLine is used.
535 g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
538 g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
540 cmdline->priv->exit_status = exit_status;
544 * g_application_command_line_get_exit_status:
545 * @cmdline: a #GApplicationCommandLine
547 * Gets the exit status of @cmdline. See
548 * g_application_command_line_set_exit_status() for more information.
550 * Returns: the exit status
555 g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
557 g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
559 return cmdline->priv->exit_status;
563 * g_application_command_line_get_platform_data:
564 * @cmdline: #GApplicationCommandLine
566 * Gets the platform data associated with the invocation of @cmdline.
568 * This is a #GVariant dictionary containing information about the
569 * context in which the invocation occured. It typically contains
570 * information like the current working directory and the startup
573 * For local invocation, it will be %NULL.
575 * Returns: the platform data, or %NULL
580 g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
582 g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
584 if (cmdline->priv->platform_data)
585 return g_variant_ref (cmdline->priv->platform_data);