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