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