[vte] Initial implementation of vte_terminal_write_contents()
- From: Behdad Esfahbod <behdad src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [vte] Initial implementation of vte_terminal_write_contents()
- Date: Wed, 13 Jan 2010 23:14:41 +0000 (UTC)
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]