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