Add missing annotations to GApplication and GApplicationCommandLine.
[platform/upstream/glib.git] / gio / gapplicationcommandline.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
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.
8  *
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.
13  *
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,
17  * USA.
18  *
19  * Authors: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gapplicationcommandline.h"
25
26 #include "glibintl.h"
27
28 #include <string.h>
29 #include <stdio.h>
30
31 G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
32
33 /**
34  * SECTION:gapplicationcommandline
35  * @title: GApplicationCommandLine
36  * @short_description: A command-line invocation of an application
37  * @see_also: #GApplication
38  *
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.
42  *
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).
48  *
49  * The exit status of the originally-invoked process may be set and
50  * messages can be printed to stdout or stderr of that process.  The
51  * lifecycle of the originally-invoked process is tied to the lifecycle
52  * of this object (ie: the process exits when the last reference is
53  * dropped).
54  *
55  * <example id="gapplication-example-cmdline"><title>Handling commandline arguments with GApplication</title>
56  * <programlisting>
57  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline.c">
58  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
59  * </xi:include>
60  * </programlisting>
61  * </example>
62  *
63  * <example id="gapplication-example-cmdline2"><title>Complicated commandline handling</title>
64  * <programlisting>
65  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline2.c">
66  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
67  * </xi:include>
68  * </programlisting>
69  * </example>
70  **/
71
72 enum
73 {
74   PROP_NONE,
75   PROP_ARGUMENTS,
76   PROP_PLATFORM_DATA,
77   PROP_IS_REMOTE
78 };
79
80 struct _GApplicationCommandLinePrivate
81 {
82   GVariant *platform_data;
83   GVariant *arguments;
84   GVariant *cwd;
85
86   const gchar **environ;
87   gint exit_status;
88 };
89
90 /* All subclasses represent remote invocations of some kind. */
91 #define IS_REMOTE(cmdline) (G_TYPE_FROM_INSTANCE (cmdline) != \
92                             G_TYPE_APPLICATION_COMMAND_LINE)
93
94 static void
95 grok_platform_data (GApplicationCommandLine *cmdline)
96 {
97   GVariantIter iter;
98   const gchar *key;
99   GVariant *value;
100
101   g_variant_iter_init (&iter, cmdline->priv->platform_data);
102
103   while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
104     if (strcmp (key, "cwd") == 0)
105       {
106         if (!cmdline->priv->cwd)
107           cmdline->priv->cwd = g_variant_ref (value);
108       }
109
110     else if (strcmp (key, "environ") == 0)
111       {
112         if (!cmdline->priv->environ)
113           cmdline->priv->environ =
114             g_variant_get_bytestring_array (value, NULL);
115       }
116 }
117
118 static void
119 g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
120                                                const gchar             *message)
121 {
122   g_print ("%s\n", message);
123 }
124
125 static void
126 g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
127                                                   const gchar             *message)
128 {
129   g_printerr ("%s\n", message);
130 }
131
132 static void
133 g_application_command_line_get_property (GObject    *object,
134                                          guint       prop_id,
135                                          GValue     *value,
136                                          GParamSpec *pspec)
137 {
138   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
139
140   switch (prop_id)
141     {
142     case PROP_ARGUMENTS:
143       g_value_set_variant (value, cmdline->priv->arguments);
144       break;
145
146     case PROP_PLATFORM_DATA:
147       g_value_set_variant (value, cmdline->priv->platform_data);
148       break;
149
150     case PROP_IS_REMOTE:
151       g_value_set_boolean (value, IS_REMOTE (cmdline));
152       break;
153
154     default:
155       g_assert_not_reached ();
156     }
157 }
158
159 static void
160 g_application_command_line_set_property (GObject      *object,
161                                          guint         prop_id,
162                                          const GValue *value,
163                                          GParamSpec   *pspec)
164 {
165   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
166
167   switch (prop_id)
168     {
169     case PROP_ARGUMENTS:
170       g_assert (cmdline->priv->arguments == NULL);
171       cmdline->priv->arguments = g_value_dup_variant (value);
172       break;
173
174     case PROP_PLATFORM_DATA:
175       g_assert (cmdline->priv->platform_data == NULL);
176       cmdline->priv->platform_data = g_value_dup_variant (value);
177       if (cmdline->priv->platform_data != NULL)
178         grok_platform_data (cmdline);
179       break;
180
181     default:
182       g_assert_not_reached ();
183     }
184 }
185
186 static void
187 g_application_command_line_finalize (GObject *object)
188 {
189   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
190
191   if (cmdline->priv->platform_data)
192     g_variant_unref (cmdline->priv->platform_data);
193   if (cmdline->priv->arguments)
194     g_variant_unref (cmdline->priv->arguments);
195   if (cmdline->priv->cwd)
196     g_variant_unref (cmdline->priv->cwd);
197
198   G_OBJECT_CLASS (g_application_command_line_parent_class)
199     ->finalize (object);
200 }
201
202 static void
203 g_application_command_line_init (GApplicationCommandLine *cmdline)
204 {
205   cmdline->priv =
206     G_TYPE_INSTANCE_GET_PRIVATE (cmdline,
207                                  G_TYPE_APPLICATION_COMMAND_LINE,
208                                  GApplicationCommandLinePrivate);
209 }
210
211 static void
212 g_application_command_line_class_init (GApplicationCommandLineClass *class)
213 {
214   GObjectClass *object_class = G_OBJECT_CLASS (class);
215
216   object_class->get_property = g_application_command_line_get_property;
217   object_class->set_property = g_application_command_line_set_property;
218   object_class->finalize = g_application_command_line_finalize;
219   class->printerr_literal = g_application_command_line_real_printerr_literal;
220   class->print_literal = g_application_command_line_real_print_literal;
221
222   g_object_class_install_property (object_class, PROP_ARGUMENTS,
223     g_param_spec_variant ("arguments",
224                           P_("Commandline arguments"),
225                           P_("The commandline that caused this ::command-line signal emission"),
226                           G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
227                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
228                           G_PARAM_STATIC_STRINGS));
229
230   g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
231     g_param_spec_variant ("platform-data",
232                           P_("Platform data"),
233                           P_("Platform-specific data for the commandline"),
234                           G_VARIANT_TYPE ("a{sv}"), NULL,
235                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
236                           G_PARAM_STATIC_STRINGS));
237
238   g_object_class_install_property (object_class, PROP_IS_REMOTE,
239     g_param_spec_boolean ("is-remote",
240                           P_("Is remote"),
241                           P_("TRUE if this is a remote commandline"),
242                           FALSE,
243                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
244
245   g_type_class_add_private (class, sizeof (GApplicationCommandLinePrivate));
246 }
247
248
249 /**
250  * g_application_command_line_get_arguments:
251  * @cmdline: a #GApplicationCommandLine
252  * @argc: (out): the length of the arguments array, or %NULL
253  *
254  * Gets the list of arguments that was passed on the command line.
255  *
256  * The strings in the array may contain non-utf8 data.
257  *
258  * The return value is %NULL-terminated and should be freed using
259  * g_strfreev().
260  *
261  * Returns: (array length=argc) (transfer full): the string array
262  * containing the arguments (the argv)
263  *
264  * Since: 2.28
265  **/
266 gchar **
267 g_application_command_line_get_arguments (GApplicationCommandLine *cmdline,
268                                           int                     *argc)
269 {
270   gchar **argv;
271   gsize len;
272
273   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
274
275   argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
276
277   if (argc)
278     *argc = len;
279
280   return argv;
281 }
282
283 /**
284  * g_application_command_line_get_cwd:
285  * @cmdline: a #GApplicationCommandLine
286  *
287  * Gets the working directory of the command line invocation.  The
288  * string may contain non-utf8 data.
289  *
290  * It is possible that the remote application did not send a working
291  * directory, so this may be %NULL.
292  *
293  * The return value should not be modified or freed and is valid for as
294  * long as @cmdline exists.
295  *
296  * Returns: the current directory, or %NULL
297  *
298  * Since: 2.28
299  **/
300 const gchar *
301 g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
302 {
303   if (cmdline->priv->cwd)
304     return g_variant_get_bytestring (cmdline->priv->cwd);
305   else
306     return NULL;
307 }
308
309 /**
310  * g_application_command_line_get_environ:
311  * @cmdline: a #GApplicationCommandLine
312  *
313  * Gets the contents of the 'environ' variable of the command line
314  * invocation, as would be returned by g_get_environ().  The strings may
315  * contain non-utf8 data.
316  *
317  * The remote application usually does not send an environment.  Use
318  * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
319  * set it is possible that the environment is still not available (due
320  * to invocation messages from other applications).
321  *
322  * The return value should not be modified or freed and is valid for as
323  * long as @cmdline exists.
324  *
325  * Returns: (array zero-terminated=1) (transfer none): the environment
326  * strings, or %NULL if they were not sent
327  * 
328  * Since: 2.28
329  **/
330 const gchar * const *
331 g_application_command_line_get_environ (GApplicationCommandLine *cmdline)
332 {
333   return cmdline->priv->environ;
334 }
335
336 /**
337  * g_application_command_line_getenv:
338  * @cmdline: a #GApplicationCommandLine
339  * @name: the environment variable to get
340  *
341  * Gets the value of a particular environment variable of the command
342  * line invocation, as would be returned by g_getenv().  The strings may
343  * contain non-utf8 data.
344  *
345  * The remote application usually does not send an environment.  Use
346  * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
347  * set it is possible that the environment is still not available (due
348  * to invocation messages from other applications).
349  *
350  * The return value should not be modified or freed and is valid for as
351  * long as @cmdline exists.
352  *
353  * Returns: the value of the variable, or %NULL if unset or unsent
354  * 
355  * Since: 2.28
356  **/
357 const gchar *
358 g_application_command_line_getenv (GApplicationCommandLine *cmdline,
359                                    const gchar             *name)
360 {
361   gint length = strlen (name);
362   gint i;
363
364   /* TODO: expand on windows */
365   if (cmdline->priv->environ)
366     for (i = 0; cmdline->priv->environ[i]; i++)
367       if (strncmp (cmdline->priv->environ[i], name, length) == 0 &&
368           cmdline->priv->environ[i][length] == '=')
369         return cmdline->priv->environ[i] + length + 1;
370
371   return NULL;
372 }
373
374 /**
375  * g_application_command_line_get_is_remote:
376  * @cmdline: a #GApplicationCommandLine
377  *
378  * Determines if @cmdline represents a remote invocation.
379  *
380  * Returns: %TRUE if the invocation was remote
381  *
382  * Since: 2.28
383  **/
384 gboolean
385 g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
386 {
387   return IS_REMOTE (cmdline);
388 }
389
390 /**
391  * g_application_command_line_print:
392  * @cmdline: a #GApplicationCommandLine
393  * @format: a printf-style format string
394  * @...: arguments, as per @format
395  *
396  * Formats a message and prints it using the stdout print handler in the
397  * invoking process.
398  *
399  * If @cmdline is a local invocation then this is exactly equivalent to
400  * g_print().  If @cmdline is remote then this is equivalent to calling
401  * g_print() in the invoking process.
402  *
403  * Since: 2.28
404  **/
405 void
406 g_application_command_line_print (GApplicationCommandLine *cmdline,
407                                   const gchar             *format,
408                                   ...)
409 {
410   gchar *message;
411   va_list ap;
412
413   g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
414   g_return_if_fail (format != NULL);
415
416   va_start (ap, format);
417   message = g_strdup_vprintf (format, ap);
418   va_end (ap);
419
420   G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
421     ->print_literal (cmdline, message);
422   g_free (message);
423 }
424
425 /**
426  * g_application_command_line_printerr:
427  * @cmdline: a #GApplicationCommandLine
428  * @format: a printf-style format string
429  * @...: arguments, as per @format
430  *
431  * Formats a message and prints it using the stderr print handler in the
432  * invoking process.
433  *
434  * If @cmdline is a local invocation then this is exactly equivalent to
435  * g_printerr().  If @cmdline is remote then this is equivalent to
436  * calling g_printerr() in the invoking process.
437  *
438  * Since: 2.28
439  **/
440 void
441 g_application_command_line_printerr (GApplicationCommandLine *cmdline,
442                                      const gchar             *format,
443                                      ...)
444 {
445   gchar *message;
446   va_list ap;
447
448   g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
449   g_return_if_fail (format != NULL);
450
451   va_start (ap, format);
452   message = g_strdup_vprintf (format, ap);
453   va_end (ap);
454
455   G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
456     ->printerr_literal (cmdline, message);
457   g_free (message);
458 }
459
460 /**
461  * g_application_command_line_set_exit_status:
462  * @cmdline: a #GApplicationCommandLine
463  * @exit_status: the exit status
464  *
465  * Sets the exit status that will be used when the invoking process
466  * exits.
467  *
468  * The return value of the #GApplication::command-line signal is
469  * passed to this function when the handler returns.  This is the usual
470  * way of setting the exit status.
471  *
472  * In the event that you want the remote invocation to continue running
473  * and want to decide on the exit status in the future, you can use this
474  * call.  For the case of a remote invocation, the remote process will
475  * typically exit when the last reference is dropped on @cmdline.  The
476  * exit status of the remote process will be equal to the last value
477  * that was set with this function.
478  *
479  * In the case that the commandline invocation is local, the situation
480  * is slightly more complicated.  If the commandline invocation results
481  * in the mainloop running (ie: because the use-count of the application
482  * increased to a non-zero value) then the application is considered to
483  * have been 'successful' in a certain sense, and the exit status is
484  * always zero.  If the application use count is zero, though, the exit
485  * status of the local #GApplicationCommandLine is used.
486  *
487  * Since: 2.28
488  **/
489 void
490 g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
491                                             int                      exit_status)
492 {
493   g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
494
495   cmdline->priv->exit_status = exit_status;
496 }
497
498 /**
499  * g_application_command_line_get_exit_status:
500  * @cmdline: a #GApplicationCommandLine
501  *
502  * Gets the exit status of @cmdline.  See
503  * g_application_command_line_set_exit_status() for more information.
504  *
505  * Returns: the exit status
506  *
507  * Since: 2.28
508  **/
509 int
510 g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
511 {
512   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
513
514   return cmdline->priv->exit_status;
515 }
516
517 /**
518  * g_application_command_line_get_platform_data:
519  * @cmdline: #GApplicationCommandLine
520  *
521  * Gets the platform data associated with the invocation of @cmdline.
522  *
523  * This is a #GVariant dictionary containing information about the
524  * context in which the invocation occured.  It typically contains
525  * information like the current working directory and the startup
526  * notification ID.
527  *
528  * For local invocation, it will be %NULL.
529  *
530  * Returns: the platform data, or %NULL
531  *
532  * Since: 2.28
533  **/
534 GVariant *
535 g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
536 {
537   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
538
539   if (cmdline->priv->platform_data)
540     return g_variant_ref (cmdline->priv->platform_data);
541   else
542       return NULL;
543 }