[vte] Initial implementation of vte_terminal_write_contents()



commit f7920a159918b81286d5345ed83a7b5ce2c5668f
Author: Behdad Esfahbod <behdad behdad org>
Date:   Wed Jan 13 18:13:30 2010 -0500

    Initial implementation of vte_terminal_write_contents()
    
    Currently is buggy in that it writes parts of history still in the ring but
    before set number of history lines.  Fix coming.

 configure.in         |    5 +--
 src/Makefile.am      |    4 +-
 src/ring.c           |   64 +++++++++++++++++++++++++++++++++++++++++++++++++-
 src/ring.h           |   12 ++++++++-
 src/vte.c            |   38 +++++++++++++++++++++++++++++-
 src/vte.h            |   19 +++++++++++++-
 src/vteapp.c         |   55 +++++++++++++++++++++++++++++++-----------
 src/vtestream-base.h |   10 +++++++-
 src/vtestream-file.h |   31 +++++++++++++++++++++++-
 src/vtestream.c      |    7 ++---
 src/vtestream.h      |    4 ++-
 11 files changed, 217 insertions(+), 32 deletions(-)
---
diff --git a/configure.in b/configure.in
index 341ef58..8bd5ef9 100644
--- a/configure.in
+++ b/configure.in
@@ -257,8 +257,7 @@ GLIB_REQUIRED=2.22.0
 PANGO_REQUIRED=1.22.0
 GTK_REQUIRED=2.14.0
 AC_DEFINE(GDK_MULTIHEAD_SAFE,1,[Force use of GDK's multihead-safe APIs.])
-PKG_CHECK_MODULES(GLIB,[glib-2.0 > $GLIB_REQUIRED])
-PKG_CHECK_MODULES(GOBJECT,[glib-2.0 gobject-2.0])
+PKG_CHECK_MODULES(GLIB,[glib-2.0 > $GLIB_REQUIRED gobject-2.0])
 PKG_CHECK_MODULES(GTK,[glib-2.0 >= $GLIB_REQUIRED gobject-2.0 gtk+-2.0 >= $GTK_REQUIRED])
 
 # Let the user specify the default terminal emulation.
@@ -335,7 +334,7 @@ case "$vte_cv_termcap_lib" in
 esac
 
 # Search for the required modules.
-VTE_PKGS="glib-2.0 >= $GLIB_REQUIRED gobject-2.0 pango >= $PANGO_REQUIRED gtk+-2.0 >= $GTK_REQUIRED"
+VTE_PKGS="glib-2.0 >= $GLIB_REQUIRED gobject-2.0 pango >= $PANGO_REQUIRED gtk+-2.0 >= $GTK_REQUIRED gobject-2.0 gio-2.0 gio-unix-2.0"
 PKG_CHECK_MODULES([VTE],[$VTE_PKGS])
 AC_SUBST([VTE_PKGS])
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 62a9a71..b980e7b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -162,8 +162,8 @@ EXTRA_DIST += $(TEST_SH)
 check_PROGRAMS = dumpkeys iso2022 pty reaper reflect-text-view reflect-vte mev ssfe table trie xticker vteconv vtetc
 TESTS = table trie $(TEST_SH)
 
-AM_CFLAGS = $(GLIB_CFLAGS) $(GOBJECT_CFLAGS)
-LDADD = $(GLIB_LIBS) $(GOBJECT_LIBS)
+AM_CFLAGS = $(GLIB_CFLAGS)
+LDADD = $(GLIB_LIBS)
 
 reflect_text_view_CPPFLAGS = -DUSE_TEXT_VIEW
 reflect_text_view_CFLAGS = $(VTE_CFLAGS)
diff --git a/src/ring.c b/src/ring.c
index 4fe0eb5..e5a7e23 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002,2009 Red Hat, Inc.
+ * Copyright (C) 2002,2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -559,3 +559,65 @@ _vte_ring_append (VteRing * ring)
 	return _vte_ring_insert (ring, _vte_ring_next (ring));
 }
 
+
+static gboolean
+_vte_ring_write_row (VteRing *ring,
+		     GOutputStream *stream,
+		     VteRowData *row,
+		     VteTerminalWriteFlags flags,
+		     GCancellable *cancellable,
+		     GError **error)
+{
+	VteCell *cell;
+	GString *buffer = ring->utf8_buffer;
+	int i;
+	gsize bytes_written;
+
+	/* Simple version of the loop in _vte_ring_freeze_row().
+	 * TODO Should unify one day */
+	g_string_set_size (buffer, 0);
+	for (i = 0, cell = row->cells; i < row->len; i++, cell++) {
+		if (G_LIKELY (!cell->attr.fragment))
+			_vte_unistr_append_to_string (cell->c, buffer);
+	}
+	if (!row->attr.soft_wrapped)
+		g_string_append_c (buffer, '\n');
+
+	return g_output_stream_write_all (stream, buffer->str, buffer->len, &bytes_written, cancellable, error);
+}
+
+/**
+ * _vte_ring_write_contents:
+ * @ring: a #VteRing
+ * @stream: a #GOutputStream to write to
+ * @flags: a set of #VteTerminalWriteFlags
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: a #GError location to store the error occuring, or %NULL to ignore
+ *
+ * Write entire ring contents to @stream according to @flags.
+ *
+ * Return: %TRUE on success, %FALSE if there was an error
+ */
+gboolean
+_vte_ring_write_contents (VteRing *ring,
+			  GOutputStream *stream,
+			  VteTerminalWriteFlags flags,
+			  GCancellable *cancellable,
+			  GError **error)
+{
+	gulong i;
+
+	_vte_debug_print(VTE_DEBUG_RING, "Writing contents to GOutputStream.\n");
+
+	if (!_vte_stream_write_contents (ring->text_stream, stream, cancellable, error))
+		return FALSE;
+
+	for (i = ring->writable; i < ring->end; i++) {
+		if (!_vte_ring_write_row (ring, stream,
+					  _vte_ring_writable_index (ring, i),
+					  flags, cancellable, error))
+			return FALSE;
+	}
+
+	return TRUE;
+}
diff --git a/src/ring.h b/src/ring.h
index 5bc2534..50dd5a2 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002,2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -14,6 +14,8 @@
  * You should have received a copy of the GNU Library General Public
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
  */
 
 /* The interfaces in this file are subject to change at any time. */
@@ -21,6 +23,9 @@
 #ifndef vte_ring_h_included
 #define vte_ring_h_included
 
+#include <gio/gio.h>
+#include "vte.h"
+
 #include "vterowdata.h"
 #include "vtestream.h"
 
@@ -75,6 +80,11 @@ void _vte_ring_shrink (VteRing *ring, gulong max_len);
 VteRowData *_vte_ring_insert (VteRing *ring, gulong position);
 VteRowData *_vte_ring_append (VteRing *ring);
 void _vte_ring_remove (VteRing *ring, gulong position);
+gboolean _vte_ring_write_contents (VteRing *ring,
+				   GOutputStream *stream,
+				   VteTerminalWriteFlags flags,
+				   GCancellable *cancellable,
+				   GError **error);
 
 G_END_DECLS
 
diff --git a/src/vte.c b/src/vte.c
index d58fd60..b0af7bc 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2004 Red Hat, Inc.
+ * Copyright (C) 2001-2004,2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -14270,3 +14270,39 @@ update_timeout (gpointer data)
 
 	return FALSE;
 }
+
+
+
+/**
+ * vte_terminal_write_contents:
+ * @terminal: a #VteTerminal
+ * @stream: a #GOutputStream to write to
+ * @flags: a set of #VteTerminalWriteFlags
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: a #GError location to store the error occuring, or %NULL to ignore
+ *
+ * Write contents of the current contents of @terminal (including any
+ * scrollback history) to @stream according to @flags.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by triggering
+ * the cancellable object from another thread. If the operation was cancelled,
+ * the error %G_IO_ERROR_CANCELLED will be returned in @error.
+ *
+ * This is a synchronous operation and will make the widget (and input
+ * processing) during the write operation, which may take a long time
+ * depending on scrollback history and @stream availability for writing.
+ *
+ * Return: %TRUE on success, %FALSE if there was an error
+ *
+ * Since: 0.24
+ */
+gboolean vte_terminal_write_contents (VteTerminal *terminal,
+				      GOutputStream *stream,
+				      VteTerminalWriteFlags flags,
+				      GCancellable *cancellable,
+				      GError **error)
+{
+	return _vte_ring_write_contents (terminal->pvt->screen->row_data,
+					 stream, flags,
+					 cancellable, error);
+}
diff --git a/src/vte.h b/src/vte.h
index 5fe448f..3b64239 100644
--- a/src/vte.h
+++ b/src/vte.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001,2002,2003 Red Hat, Inc.
+ * Copyright (C) 2001,2002,2003,2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -20,8 +20,9 @@
 #define vte_vte_h_included
 
 #include <glib.h>
-#include <gtk/gtk.h>
+#include <gio/gio.h>
 #include <pango/pango.h>
+#include <gtk/gtk.h>
 
 #include <sys/types.h> /* for pid_t */
 
@@ -417,6 +418,20 @@ const char *vte_terminal_get_icon_title(VteTerminal *terminal);
 
 int vte_terminal_get_child_exit_status(VteTerminal *terminal);
 
+
+/* Writing contents out */
+
+typedef enum {
+  VTE_TERMINAL_WRITE_DEFAULT = 0
+} VteTerminalWriteFlags;
+
+gboolean vte_terminal_write_contents (VteTerminal *terminal,
+				      GOutputStream *stream,
+				      VteTerminalWriteFlags flags,
+				      GCancellable *cancellable,
+				      GError **error);
+
+
 #ifndef VTE_DISABLE_DEPRECATED
 
 #define VTE_IS_TERMINAL_ERASE_BINDING(obj)  (FALSE)
diff --git a/src/vteapp.c b/src/vteapp.c
index d5a90ca..eb285a8 100644
--- a/src/vteapp.c
+++ b/src/vteapp.c
@@ -130,26 +130,46 @@ char_size_realized(GtkWidget *widget, gpointer data)
 				      GDK_HINT_MIN_SIZE);
 }
 
-static void
-deleted_and_quit(GtkWidget *widget, GdkEvent *event, gpointer data)
-{
-	gtk_widget_destroy(GTK_WIDGET(data));
-	gtk_main_quit();
-}
 
 static void
 destroy_and_quit(GtkWidget *widget, gpointer data)
 {
+	const char *output_file = g_object_get_data (G_OBJECT (widget), "output_file");
+
+	if (output_file) {
+		VteTerminal *terminal = VTE_TERMINAL (widget);
+		GFile *file;
+		GOutputStream *stream;
+		GError *error = NULL;
+
+		file = g_file_new_for_commandline_arg (output_file);
+		stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
+
+		if (stream) {
+			vte_terminal_write_contents (terminal, stream,
+						     VTE_TERMINAL_WRITE_DEFAULT,
+						     NULL, &error);
+			g_object_unref (stream);
+		}
+
+		if (error) {
+			g_printerr ("%s\n", error->message);
+			g_error_free (error);
+		}
+
+		g_object_unref (file);
+	}
+
 	gtk_widget_destroy(GTK_WIDGET(data));
 	gtk_main_quit();
 }
 static void
-destroy_and_quit_eof(GtkWidget *widget, gpointer data)
+delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
-	_vte_debug_print(VTE_DEBUG_MISC, "Detected EOF.\n");
+	destroy_and_quit(widget, data);
 }
 static void
-destroy_and_quit_exited(GtkWidget *widget, gpointer data)
+child_exited(GtkWidget *widget, gpointer data)
 {
 	_vte_debug_print(VTE_DEBUG_MISC, "Detected child exit.\n");
 	destroy_and_quit(widget, data);
@@ -469,6 +489,7 @@ main(int argc, char **argv)
 	const char *termcap = NULL;
 	const char *command = NULL;
 	const char *working_directory = NULL;
+	const char *output_file = NULL;
         char *cursor_shape = NULL;
 	GdkColor fore, back, tint, highlight, cursor;
 	const GOptionEntry options[]={
@@ -613,6 +634,11 @@ main(int argc, char **argv)
 			"Print VteTerminal object notifications",
 			NULL
 		},
+		{
+			"output-file", 0, 0,
+			G_OPTION_ARG_STRING, &output_file,
+			"Save terminal contents to file at exit", NULL
+		},
 		{ NULL }
 	};
 	GOptionContext *context;
@@ -659,7 +685,7 @@ main(int argc, char **argv)
 	gtk_container_set_resize_mode(GTK_CONTAINER(window),
 				      GTK_RESIZE_IMMEDIATE);
 	g_signal_connect(window, "delete-event",
-			 G_CALLBACK(deleted_and_quit), window);
+			 G_CALLBACK(delete_event), window);
 
 	/* Set ARGB colormap */
 	screen = gtk_widget_get_screen (window);
@@ -713,11 +739,9 @@ main(int argc, char **argv)
 				 G_CALLBACK(icon_title_changed), window);
 	}
 
-	/* Connect to the "eof" signal to quit when the session ends. */
-	g_signal_connect(widget, "eof",
-			 G_CALLBACK(destroy_and_quit_eof), window);
+	/* Connect to the "child-exited" signal to quit when the session ends. */
 	g_signal_connect(widget, "child-exited",
-			 G_CALLBACK(destroy_and_quit_exited), window);
+			 G_CALLBACK(child_exited), window);
 
 	/* Connect to the "status-line-changed" signal. */
 	g_signal_connect(widget, "status-line-changed",
@@ -913,6 +937,8 @@ main(int argc, char **argv)
 		}
 	}
 
+	g_object_set_data (G_OBJECT (widget), "output_file", (gpointer) output_file);
+
 	/* Go for it! */
 	add_weak_pointer(G_OBJECT(widget), &widget);
 	add_weak_pointer(G_OBJECT(window), &window);
@@ -926,7 +952,6 @@ main(int argc, char **argv)
 
 	gtk_widget_show_all(window);
 
-
 	gtk_main();
 
 	g_assert(widget == NULL);
diff --git a/src/vtestream-base.h b/src/vtestream-base.h
index 6b4347a..74b7301 100644
--- a/src/vtestream-base.h
+++ b/src/vtestream-base.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -19,6 +19,7 @@
  */
 
 #include <glib-object.h>
+#include <gio/gio.h>
 
 /*
  * VteStream: Abstract base stream class
@@ -37,6 +38,7 @@ typedef struct _VteStreamClass {
 	void (*truncate) (VteStream *stream, gsize offset);
 	void (*new_page) (VteStream *stream);
 	gsize (*head) (VteStream *stream);
+	gboolean (*write_contents) (VteStream *stream, GOutputStream *output, GCancellable *cancellable, GError **error);
 } VteStreamClass;
 
 static GType _vte_stream_get_type (void);
@@ -90,3 +92,9 @@ _vte_stream_head (VteStream *stream)
 {
 	return VTE_STREAM_GET_CLASS (stream)->head (stream);
 }
+
+gboolean
+_vte_stream_write_contents (VteStream *stream, GOutputStream *output, GCancellable *cancellable, GError **error)
+{
+	return VTE_STREAM_GET_CLASS (stream)->write_contents (stream, output, cancellable, error);
+}
diff --git a/src/vtestream-file.h b/src/vtestream-file.h
index 1701af3..707877b 100644
--- a/src/vtestream-file.h
+++ b/src/vtestream-file.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -22,6 +22,8 @@
 #include <unistd.h>
 #include <errno.h>
 
+#include <gio/gunixinputstream.h>
+
 static gsize
 _xread (int fd, char *data, gsize len)
 {
@@ -82,6 +84,23 @@ _xtruncate (gint fd, gsize offset)
 	} while (ret == -1 && errno == EINTR);
 }
 
+static gboolean
+_xwrite_contents (gint fd, GOutputStream *output, GCancellable *cancellable, GError **error)
+{
+	gboolean ret;
+	GInputStream *input;
+
+	if (G_UNLIKELY (!fd))
+		return TRUE;
+
+	lseek (fd, 0, SEEK_SET);
+	input = g_unix_input_stream_new (fd, FALSE);
+	ret = -1 != g_output_stream_splice (output, input, G_OUTPUT_STREAM_SPLICE_NONE, cancellable, error);
+	g_object_unref (input);
+
+	return ret;
+}
+
 
 /*
  * VteFileStream: A POSIX file-based stream
@@ -240,6 +259,15 @@ _vte_file_stream_head (VteStream *astream)
 		return stream->offset[0];
 }
 
+static gboolean
+_vte_file_stream_write_contents (VteStream *astream, GOutputStream *output, GCancellable *cancellable, GError **error)
+{
+	VteFileStream *stream = (VteFileStream *) astream;
+
+	return _xwrite_contents (stream->fd[1], output, cancellable, error) &&
+	       _xwrite_contents (stream->fd[0], output, cancellable, error);
+}
+
 static void
 _vte_file_stream_class_init (VteFileStreamClass *klass)
 {
@@ -253,4 +281,5 @@ _vte_file_stream_class_init (VteFileStreamClass *klass)
 	klass->truncate = _vte_file_stream_truncate;
 	klass->new_page = _vte_file_stream_new_page;
 	klass->head = _vte_file_stream_head;
+	klass->write_contents = _vte_file_stream_write_contents;
 }
diff --git a/src/vtestream.c b/src/vtestream.c
index 8b31c9a..ab90948 100644
--- a/src/vtestream.c
+++ b/src/vtestream.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -25,9 +25,8 @@
 
 
 /*
- * Note: Lot of this should have become possible using gio, not sure though.
- * In paticular, I don't see input+output streams in gio, so we probably would
- * have to reinvent it all ourselves anyway.
+ * In the future it may be worth replacing these with gio.  Not sure about
+ * the overhead though.
  */
 
 #include "vtestream-base.h"
diff --git a/src/vtestream.h b/src/vtestream.h
index 56df5a0..f21e8b0 100644
--- a/src/vtestream.h
+++ b/src/vtestream.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009,2010 Red Hat, Inc.
  *
  * This is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Library General Public License as published by
@@ -22,6 +22,7 @@
 #define vtestream_h_included
 
 #include <glib-object.h>
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
@@ -33,6 +34,7 @@ gboolean _vte_stream_read (VteStream *stream, gsize offset, char *data, gsize le
 void _vte_stream_truncate (VteStream *stream, gsize offset);
 void _vte_stream_new_page (VteStream *stream);
 gsize _vte_stream_head (VteStream *stream);
+gboolean _vte_stream_write_contents (VteStream *stream, GOutputStream *output, GCancellable *cancellable, GError **error);
 
 
 /* Various streams */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]