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