From 89d48d7800a21db1b94c09644bc68b84cda1940b Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Wed, 18 Jan 2012 14:37:37 -0500 Subject: [PATCH] Add g_application_command_line_get_stdin() This returns a GInputStream corresponding to the stdin on the commandline that caused this invocation. The local case works on both UNIX (GUnixInputStream on stdin) and Windows (GWin32InputStream on GetStdHandle(STD_INPUT_HANDLE)). The remote case works only on UNIX (by fd passing over D-Bus). https://bugzilla.gnome.org/show_bug.cgi?id=668210 --- gio/gapplicationcommandline.c | 46 ++++++++++++++++++++++ gio/gapplicationcommandline.h | 13 ++++--- gio/gapplicationimpl-dbus.c | 73 ++++++++++++++++++++++++++++++----- gio/gio.symbols | 1 + 4 files changed, 119 insertions(+), 14 deletions(-) diff --git a/gio/gapplicationcommandline.c b/gio/gapplicationcommandline.c index 9b8485444..b2da4b199 100644 --- a/gio/gapplicationcommandline.c +++ b/gio/gapplicationcommandline.c @@ -29,6 +29,16 @@ #include #include +#ifdef G_OS_UNIX +#include "gunixinputstream.h" +#endif + +#ifdef G_OS_WIN32 +#include +#undef environ +#include "gwin32inputstream.h" +#endif + G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT) /** @@ -188,6 +198,16 @@ g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdli g_printerr ("%s", message); } +static GInputStream * +g_application_command_line_real_get_stdin (GApplicationCommandLine *cmdline) +{ +#ifdef G_OS_UNIX + return g_unix_input_stream_new (0, FALSE); +#else + return g_win32_input_stream_new (GetStdHandle (STD_INPUT_HANDLE), FALSE); +#endif +} + static void g_application_command_line_get_property (GObject *object, guint prop_id, @@ -296,6 +316,7 @@ g_application_command_line_class_init (GApplicationCommandLineClass *class) class->printerr_literal = g_application_command_line_real_printerr_literal; class->print_literal = g_application_command_line_real_print_literal; + class->get_stdin = g_application_command_line_real_get_stdin; g_object_class_install_property (object_class, PROP_ARGUMENTS, g_param_spec_variant ("arguments", @@ -358,6 +379,31 @@ g_application_command_line_get_arguments (GApplicationCommandLine *cmdline, return argv; } +/** + * g_application_command_line_get_stdin_data: + * @cmdline: a #GApplicationCommandLine + * + * Gets the stdin of the invoking process. + * + * The #GInputStream can be used to read data passed to the standard + * input of the invoking process. + * This doesn't work on all platforms. Presently, it is only available + * on UNIX when using a DBus daemon capable of passing file descriptors. + * If stdin is not available then %NULL will be returned. In the + * future, support may be expanded to other platforms. + * + * You must only call this function once per commandline invocation. + * + * Returns: (transfer full): a #GInputStream for stdin + * + * Since: 2.34 + **/ +GInputStream * +g_application_command_line_get_stdin (GApplicationCommandLine *cmdline) +{ + return G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)->get_stdin (cmdline); +} + /** * g_application_command_line_get_cwd: * @cmdline: a #GApplicationCommandLine diff --git a/gio/gapplicationcommandline.h b/gio/gapplicationcommandline.h index 8b6b094ba..cf5e5e093 100644 --- a/gio/gapplicationcommandline.h +++ b/gio/gapplicationcommandline.h @@ -62,12 +62,13 @@ struct _GApplicationCommandLineClass /*< private >*/ GObjectClass parent_class; - void (* print_literal) (GApplicationCommandLine *cmdline, - const gchar *message); - void (* printerr_literal) (GApplicationCommandLine *cmdline, - const gchar *message); + void (* print_literal) (GApplicationCommandLine *cmdline, + const gchar *message); + void (* printerr_literal) (GApplicationCommandLine *cmdline, + const gchar *message); + GInputStream * (* get_stdin) (GApplicationCommandLine *cmdline); - gpointer padding[12]; + gpointer padding[11]; }; GType g_application_command_line_get_type (void) G_GNUC_CONST; @@ -75,6 +76,8 @@ GType g_application_command_line_get_type (void) G gchar ** g_application_command_line_get_arguments (GApplicationCommandLine *cmdline, int *argc); +GInputStream * g_application_command_line_get_stdin (GApplicationCommandLine *cmdline); + const gchar * const * g_application_command_line_get_environ (GApplicationCommandLine *cmdline); const gchar * g_application_command_line_getenv (GApplicationCommandLine *cmdline, diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c index e1ed3561a..423964088 100644 --- a/gio/gapplicationimpl-dbus.c +++ b/gio/gapplicationimpl-dbus.c @@ -39,6 +39,11 @@ #include "gapplicationcommandline.h" #include "gdbusmethodinvocation.h" +#ifdef G_OS_UNIX +#include "gunixinputstream.h" +#include "gunixfdlist.h" +#endif + /* DBus Interface definition {{{1 */ /* For documentation of these interfaces, see @@ -524,8 +529,12 @@ g_application_impl_cmdline_done (GObject *source, GError *error = NULL; GVariant *reply; - reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), - result, &error); +#ifdef G_OS_UNIX + reply = g_dbus_connection_call_with_unix_fd_list_finish (G_DBUS_CONNECTION (source), NULL, result, &error); +#else + reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); +#endif + if (reply != NULL) { @@ -580,15 +589,31 @@ g_application_impl_command_line (GApplicationImpl *impl, /* In theory we should try other paths... */ g_assert (object_id != 0); - g_dbus_connection_call (impl->session_bus, - impl->bus_name, - impl->object_path, - "org.gtk.Application", - "CommandLine", - g_variant_new ("(o^aay@a{sv})", object_path, - arguments, platform_data), +#ifdef G_OS_UNIX + { + GError *error = NULL; + GUnixFDList *fd_list; + + /* send along the stdin in case + * g_application_command_line_get_stdin_data() is called + */ + fd_list = g_unix_fd_list_new (); + g_unix_fd_list_append (fd_list, 0, &error); + g_assert_no_error (error); + + g_dbus_connection_call_with_unix_fd_list (impl->session_bus, impl->bus_name, impl->object_path, + "org.gtk.Application", "CommandLine", + g_variant_new ("(o^aay@a{sv})", object_path, arguments, platform_data), + G_VARIANT_TYPE ("(i)"), 0, G_MAXINT, fd_list, NULL, + g_application_impl_cmdline_done, &data); + } +#else + g_dbus_connection_call (impl->session_bus, impl->bus_name, impl->object_path, + "org.gtk.Application", "CommandLine", + g_variant_new ("(o^aay@a{sv})", object_path, arguments, platform_data), G_VARIANT_TYPE ("(i)"), 0, G_MAXINT, NULL, g_application_impl_cmdline_done, &data); +#endif g_main_loop_run (data.loop); @@ -665,6 +690,35 @@ g_dbus_command_line_printerr_literal (GApplicationCommandLine *cmdline, NULL, 0, -1, NULL, NULL, NULL); } +static GInputStream * +g_dbus_command_line_get_stdin (GApplicationCommandLine *cmdline) +{ +#ifdef G_OS_UNIX + GDBusCommandLine *gdbcl = (GDBusCommandLine *) cmdline; + GInputStream *result = NULL; + GDBusMessage *message; + GUnixFDList *fd_list; + + message = g_dbus_method_invocation_get_message (gdbcl->invocation); + fd_list = g_dbus_message_get_unix_fd_list (message); + + if (fd_list && g_unix_fd_list_get_length (fd_list)) + { + gint *fds, n_fds, i; + + fds = g_unix_fd_list_steal_fds (fd_list, &n_fds); + result = g_unix_input_stream_new (fds[0], TRUE); + for (i = 1; i < n_fds; i++) + close (fds[i]); + g_free (fds); + } + + return result; +#else + return NULL; +#endif +} + static void g_dbus_command_line_finalize (GObject *object) { @@ -695,6 +749,7 @@ g_dbus_command_line_class_init (GApplicationCommandLineClass *class) object_class->finalize = g_dbus_command_line_finalize; class->printerr_literal = g_dbus_command_line_printerr_literal; class->print_literal = g_dbus_command_line_print_literal; + class->get_stdin = g_dbus_command_line_get_stdin; } static GApplicationCommandLine * diff --git a/gio/gio.symbols b/gio/gio.symbols index 19503474e..3ae21bdd4 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -34,6 +34,7 @@ g_application_set_default g_application_set_flags g_application_set_inactivity_timeout g_application_quit +g_application_command_line_get_stdin g_application_command_line_create_file_for_arg g_application_command_line_get_arguments g_application_command_line_get_cwd