Index: python/vte-demo.py
===================================================================
--- python/vte-demo.py	(revision 2023)
+++ python/vte-demo.py	(working copy)
@@ -1,5 +1,6 @@
 #!/usr/bin/python
 import sys
+import os
 import string
 import getopt
 import gtk
@@ -19,6 +20,10 @@
 def child_exited_cb(terminal):
 	gtk.main_quit()
 
+def child_setup_func(fd):
+	os.dup2(fd, 0)
+	os.close(fd)
+
 if __name__ == '__main__':
 	child_pid = -1;
 	# Defaults.
@@ -31,8 +36,9 @@
 	scrollback = 100
 	transparent = 0
 	visible = 0
+	read_stdin = False
 	# Let the user override them.
-	(shorts, longs) = getopt.getopt(sys.argv[1:], "B:Tabc:f:n:t:v", ["background", "transparent", "audible", "blink", "command=", "font=", "scrollback=", "terminal=", "visible"])
+	(shorts, longs) = getopt.getopt(sys.argv[1:], "B:Tabc:f:n:t:v", ["background", "transparent", "audible", "blink", "command=", "font=", "scrollback=", "terminal=", "visible", "stdin"])
 	for argpair in (shorts + longs):
 		if ((argpair[0] == '-B') or (argpair[0] == '--background')):
 			print "Setting background image to `" + argpair[1] + "'."
@@ -64,6 +70,8 @@
 		if ((argpair[0] == '-v') or (argpair[0] == '--visible')):
 			print "Setting visible bell."
 			visible = not visible
+		if argpair[0] == '--stdin':
+			read_stdin = True
 	window = gtk.Window()
 	terminal = vte.Terminal()
 	if (background):
@@ -78,12 +86,18 @@
 	terminal.set_visible_bell(visible)
 	terminal.connect("child-exited", child_exited_cb)
 	terminal.connect("restore-window", restore_cb)
+	kwargs = {}
+	if read_stdin:
+		kwargs['setup'] = child_setup_func
+		kwargs['setup_data'] = os.dup(0)
 	if (command):
 		# Start up the specified command.
-		child_pid = terminal.fork_command(command)
+		child_pid = terminal.fork_command(command, **kwargs)
 	else:
 		# Start up the default command, the user's shell.
-		child_pid = terminal.fork_command()
+		child_pid = terminal.fork_command(**kwargs)
+	if read_stdin:
+		os.close(kwargs['setup_data'])
 	terminal.show()
 
 	scrollbar = gtk.VScrollbar()
Index: python/vte.override
===================================================================
--- python/vte.override	(revision 2023)
+++ python/vte.override	(working copy)
@@ -100,27 +100,66 @@
 	Py_INCREF(Py_None);
 	return Py_None;
 }
+
 %%
 override vte_terminal_fork_command kwargs
 
 static PyObject *
 _wrap_vte_terminal_fork_command(PyGObject * self, PyObject * args,
-				PyObject * kwargs)
+                  		PyObject * kwargs)
 {
+	/* All the arguments are optional, and _with_setup is just a superset,
+	 * so just delegate to that. */
+	return _wrap_vte_terminal_fork_command_with_setup(self, args, kwargs);
+}
+
+%%
+override vte_terminal_fork_command_with_setup kwargs
+
+static void
+handler_marshal(gpointer user_data)
+{
+    PyObject *tuple, *ret;
+    PyGILState_STATE state;
+
+    g_return_if_fail(user_data != NULL);
+
+    state = pyg_gil_state_ensure();
+
+    tuple = (PyObject *)user_data;
+    ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0),
+			      PyTuple_GetItem(tuple, 1));
+    if (!ret) {
+	PyErr_Print();
+    } else {
+	Py_DECREF(ret);
+    }
+    
+    pyg_gil_state_release(state);
+}
+
+static PyObject *
+_wrap_vte_terminal_fork_command_with_setup(PyGObject * self, PyObject * args,
+                  			   PyObject * kwargs)
+{
 	gchar **argv = NULL, **envv = NULL;
 	gchar *command = NULL, *directory = NULL;
+	PyObject *setup_args = NULL;
 	static char *kwlist[] = { "command", "argv", "envv", "directory",
 				  "loglastlog", "logutmp", "logwtmp",
+				  "setup", "setup_data",
 				  NULL };
 	PyObject *py_argv = NULL, *py_envv = NULL,
-		 *loglastlog = NULL, *logutmp = NULL, *logwtmp = NULL;
+		 *loglastlog = NULL, *logutmp = NULL, *logwtmp = NULL,
+		 *py_setup = NULL, *py_setup_data = NULL;
 	int i, n_args, n_envs;
 	pid_t pid;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sOOsOOO:fork_command",
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sOOsOOOOO:fork_command",
 					 kwlist, &command, &py_argv, &py_envv,
 					 &directory,
-					 &loglastlog, &logutmp, &logwtmp)) {
+					 &loglastlog, &logutmp, &logwtmp,
+					 &py_setup, &py_setup_data)) {
 		return NULL;
 	}
 
@@ -158,15 +197,33 @@
 		}
 		envv[n_envs] = NULL;
 	}
+	
+	if (py_setup != NULL) {
+		if (!PyCallable_Check(py_setup)) {
+			PyErr_SetString(PyExc_TypeError,
+					"setup must be callable");
+			return NULL;
+		}
+		if (py_setup_data) {
+			setup_args = Py_BuildValue("(O(O))", py_setup, py_setup_data);
+			if (setup_args == NULL)
+				return NULL;
+		} else {
+			setup_args = Py_BuildValue("(O())", py_setup);
+			if (setup_args == NULL)
+				return NULL;	
+		}
+	}
 
-	pid = vte_terminal_fork_command(VTE_TERMINAL(self->obj),
+	pid = vte_terminal_fork_command_with_setup(VTE_TERMINAL(self->obj),
 					command, argv, envv, directory,
 					(loglastlog != NULL) &&
 					PyObject_IsTrue(loglastlog),
 					(logutmp != NULL) &&
 					PyObject_IsTrue(logutmp),
 					(logwtmp != NULL) &&
-					PyObject_IsTrue(logwtmp));
+					PyObject_IsTrue(logwtmp),
+					py_setup != NULL ? handler_marshal : NULL, setup_args);
 
 	if (envv) {
 		g_free(envv);
@@ -175,9 +232,12 @@
 	if (argv) {
 		g_free(argv);
 	}
+	
+	Py_XDECREF(setup_args);
 
 	return PyInt_FromLong(pid);
 }
+
 %%
 override vte_terminal_forkpty kwargs
 
Index: python/vte.defs
===================================================================
--- python/vte.defs	(revision 2023)
+++ python/vte.defs	(working copy)
@@ -56,6 +56,23 @@
   (return-type "GtkWidget*")
 )
 
+(define-method fork_command_with_setup
+  (of-object "VteTerminal")
+  (c-name "vte_terminal_fork_command_with_setup")
+  (return-type "pid_t")
+  (parameters
+    '("const-char*" "command")
+    '("char**" "argv")
+    '("char**" "envv")
+    '("const-char*" "directory")
+    '("gboolean" "lastlog")
+    '("gboolean" "utmp")
+    '("gboolean" "wtmp")
+    '("GSpawnChildSetupFunc" "setup")
+    '("void*" "setup_data")
+  )
+)
+
 (define-method fork_command
   (of-object "VteTerminal")
   (c-name "vte_terminal_fork_command")
Index: src/vte.c
===================================================================
--- src/vte.c	(revision 2023)
+++ src/vte.c	(working copy)
@@ -2874,7 +2874,8 @@
 _vte_terminal_fork_basic(VteTerminal *terminal, const char *command,
 			 char **argv, char **envv,
 			 const char *directory,
-			 gboolean lastlog, gboolean utmp, gboolean wtmp)
+			 gboolean lastlog, gboolean utmp, gboolean wtmp,
+			 GSpawnChildSetupFunc setup, gpointer setup_data)
 {
 	char **env_add;
 	int i;
@@ -2902,7 +2903,7 @@
 	pid = -1;
 	i = _vte_pty_open(&pid, env_add, command, argv, directory,
 			  terminal->column_count, terminal->row_count,
-			  lastlog, utmp, wtmp);
+			  lastlog, utmp, wtmp, setup, setup_data);
 	switch (i) {
 	case -1:
 		return -1;
@@ -2989,6 +2990,37 @@
 			  const char *directory,
 			  gboolean lastlog, gboolean utmp, gboolean wtmp)
 {
+	return vte_terminal_fork_command_with_setup(terminal, command, argv, envv,
+			directory, lastlog, utmp, wtmp, NULL, NULL);
+}
+
+/**
+ * vte_terminal_fork_command_with_setup:
+ * @terminal: a #VteTerminal
+ * @command: the name of a binary to run, or %NULL to get user's shell
+ * @argv: the argument list to be passed to @command, or %NULL
+ * @envv: a list of environment variables to be added to the environment before
+ * starting @command, or %NULL
+ * @directory: the name of a directory the command should start in, or %NULL
+ * @lastlog: %TRUE if the session should be logged to the lastlog
+ * @utmp: %TRUE if the session should be logged to the utmp/utmpx log
+ * @wtmp: %TRUE if the session should be logged to the wtmp/wtmpx log
+ * @setup: A callback run in the forked child process just before execution
+ * @setup_data: User data passed to the setup function
+ *
+ * Similar to vte_terminal_fork_command, but allows further setup in
+ * the child process.
+ * 
+ * Returns: the ID of the new process
+ */
+pid_t
+vte_terminal_fork_command_with_setup(VteTerminal *terminal,
+			  const char *command, char **argv, char **envv,
+			  const char *directory,
+			  gboolean lastlog, gboolean utmp, gboolean wtmp,
+			  GSpawnChildSetupFunc setup,
+			  gpointer setup_data)
+{
 	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
 
 	/* Make the user's shell the default command. */
@@ -3022,7 +3054,7 @@
 
 	/* Start up the command and get the PTY of the master. */
 	return _vte_terminal_fork_basic(terminal, command, argv, envv,
-				        directory, lastlog, utmp, wtmp);
+				        directory, lastlog, utmp, wtmp, setup, setup_data);	
 }
 
 /**
@@ -3054,7 +3086,7 @@
 	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
 
 	return _vte_terminal_fork_basic(terminal, NULL, NULL, envv,
-				       directory, lastlog, utmp, wtmp);
+				       directory, lastlog, utmp, wtmp, NULL, NULL);
 }
 
 /* Handle an EOF from the client. */
Index: src/vte.h
===================================================================
--- src/vte.h	(revision 2023)
+++ src/vte.h	(working copy)
@@ -205,6 +205,14 @@
 				gboolean lastlog,
 				gboolean utmp,
 				gboolean wtmp);
+pid_t vte_terminal_fork_command_with_setup(VteTerminal *terminal,
+				const char *command, char **argv,
+				char **envv, const char *directory,
+				gboolean lastlog,
+				gboolean utmp,
+				gboolean wtmp,
+				GSpawnChildSetupFunc setup,
+				gpointer setup_data);
 
 /* Users of libzvt may find this useful. */
 pid_t vte_terminal_forkpty(VteTerminal *terminal,
Index: src/pty.c
===================================================================
--- src/pty.c	(revision 2023)
+++ src/pty.c	(working copy)
@@ -155,6 +155,8 @@
 		const char *name;
 		int fd;
 	} tty;
+	GSpawnChildSetupFunc user_setup;
+	gpointer user_setup_data;
 };
 static void
 vte_pty_child_setup (gpointer arg)
@@ -252,6 +254,11 @@
 	/* Reset our signals -- our parent may have done any number of
 	 * weird things to them. */
 	_vte_pty_reset_signal_handlers();
+	
+	/* We call this at the end to allow the user to override anything above,
+	 * such as the choice of stdin file descriptor. */
+	if (data->user_setup)
+		data->user_setup(data->user_setup_data);
 }
 
 /* TODO: clean up the spawning
@@ -408,12 +415,15 @@
 _vte_pty_fork_on_pty_name (const char *path, int parent_fd, char **envp,
 			   const char *command, char **argv,
 			   const char *directory,
-			   int columns, int rows, GPid *child)
+			   int columns, int rows, GSpawnChildSetupFunc setup,
+			   gpointer setup_data, GPid *child)
 {
 	struct vte_pty_child_setup_data data;
 
 	data.mode = TTY_OPEN_BY_NAME;
 	data.tty.name = path;
+	data.user_setup = setup;
+	data.user_setup_data = setup_data;
 
 	if (!_vte_pty_run_on_pty(&data,
 			command, argv, envp, directory,
@@ -432,12 +442,15 @@
 _vte_pty_fork_on_pty_fd (int fd, char **envp,
 			 const char *command, char **argv,
 			 const char *directory,
-			 int columns, int rows, GPid *child)
+			 int columns, int rows, GSpawnChildSetupFunc setup,
+			 gpointer setup_data, GPid *child)
 {
 	struct vte_pty_child_setup_data data;
 
 	data.mode = TTY_OPEN_BY_FD;
 	data.tty.fd = fd;
+	data.user_setup = setup;
+	data.user_setup_data = setup_data;	
 
 	if (!_vte_pty_run_on_pty(&data,
 				command, argv, envp, directory,
@@ -604,7 +617,8 @@
 static int
 _vte_pty_open_unix98(GPid *child, char **env_add,
 		     const char *command, char **argv,
-		     const char *directory, int columns, int rows)
+		     const char *directory, int columns, int rows,
+		     GSpawnChildSetupFunc setup, gpointer setup_data)
 {
 	int fd;
 	char *buf;
@@ -627,6 +641,7 @@
 						      env_add, command,
 						      argv, directory,
 						      columns, rows,
+						      setup, setup_data,
 						      child)) {
 				close(fd);
 				fd = -1;
@@ -880,7 +895,9 @@
 _vte_pty_open_with_helper(GPid *child, char **env_add,
 			  const char *command, char **argv,
 			  const char *directory,
-			  int columns, int rows, int op)
+			  int columns, int rows, 
+			  GSpawnChildSetupFunc setup, gpointer setup_data,
+			  int op)
 {
 	GnomePtyOps ops;
 	int ret;
@@ -936,7 +953,7 @@
 		/* Start up a child process with the given command. */
 		if (!_vte_pty_fork_on_pty_fd(childfd, env_add, command,
 					    argv, directory,
-					    columns, rows, child)) {
+					    columns, rows, setup, setup_data, child)) {
 			close(parentfd);
 			close(childfd);
 			return -1;
@@ -960,6 +977,8 @@
  * @lastlog: %TRUE if the lastlog should be updated
  * @utmp: %TRUE if the utmp or utmpx log should be updated
  * @wtmp: %TRUE if the wtmp or wtmpx log should be updated
+ * @setup: A callback run in the forked child process just before execution
+ * @setup_data Data passed to setup callback
  *
  * Starts a new copy of @command running under a psuedo-terminal, optionally in
  * the supplied @directory, with window size set to @rows x @columns
@@ -973,7 +992,8 @@
 _vte_pty_open(pid_t *child_pid, char **env_add,
 	      const char *command, char **argv, const char *directory,
 	      int columns, int rows,
-	      gboolean lastlog, gboolean utmp, gboolean wtmp)
+	      gboolean lastlog, gboolean utmp, gboolean wtmp,
+	      GSpawnChildSetupFunc setup, gpointer setup_data)
 {
 	GPid child;
 	int ret = -1;
@@ -1003,12 +1023,12 @@
 	if (ret == -1) {
 		ret = _vte_pty_open_with_helper(&child, env_add, command, argv,
 						directory,
-						columns, rows, opmap[op]);
+						columns, rows, setup, setup_data, opmap[op]);
 	}
 #endif
 	if (ret == -1) {
 		ret = _vte_pty_open_unix98(&child, env_add, command, argv,
-					   directory, columns, rows);
+					   directory, columns, rows, setup, setup_data);
 	}
 	if (ret != -1) {
 		*child_pid = (pid_t) child;
Index: src/pty.h
===================================================================
--- src/pty.h	(revision 2023)
+++ src/pty.h	(working copy)
@@ -30,7 +30,8 @@
 int _vte_pty_open(pid_t *child, char **env_add,
 		  const char *command, char **argv, const char *directory,
 		  int columns, int rows,
-		  gboolean lastlog, gboolean utmp, gboolean wtmp);
+		  gboolean lastlog, gboolean utmp, gboolean wtmp,
+		  GSpawnChildSetupFunc setup, gpointer setup_data);
 
 /* Set or read the size of a terminal.  Returns 0 on success, -1 on failure,
  * with errno set to defined return codes from ioctl(). */
