From 1ca2e621d1bdeb441a0a4448f82b499f357605ed Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Wed, 22 Jun 2005 22:13:12 +0000 Subject: [PATCH] implemented MooTermVt for unix --- moo/mooterm/Makefile.am | 56 +++- moo/mooterm/mooterm.c | 12 + moo/mooterm/mooterm.h | 5 + moo/mooterm/mootermvt-unix.c | 499 ++++++++++++++++++++++++++++++++++ moo/mooterm/mootermvt-win32.c | 16 ++ moo/mooterm/mootermvt.c | 61 ++++- moo/mooterm/mootermvt.h | 49 +++- tests/Makefile.am | 11 +- tests/mterm.cpp | 103 ++----- tests/termbuffer.cpp | 130 +++++++++ 10 files changed, 838 insertions(+), 104 deletions(-) create mode 100644 moo/mooterm/mootermvt-unix.c create mode 100644 moo/mooterm/mootermvt-win32.c create mode 100644 tests/termbuffer.cpp diff --git a/moo/mooterm/Makefile.am b/moo/mooterm/Makefile.am index 21c40a32..fe3adf29 100644 --- a/moo/mooterm/Makefile.am +++ b/moo/mooterm/Makefile.am @@ -20,6 +20,14 @@ widget_sources = \ mootermvt.c \ mootermvt.h +widget_unix_sources = \ + mootermvt-unix.c \ + pty.c \ + pty.h + +widget_win32_sources = \ + mootermvt-win32.c + AM_INCLUDES = common_cflags = \ -I$(top_builddir) \ @@ -29,9 +37,55 @@ common_cflags = \ $(PYGTK_CFLAGS) \ $(GTK_CFLAGS) \ -DG_LOG_DOMAIN=\"Moo\" + AM_CFLAGS = $(common_cflags) $(M_CFLAGS) $(CFLAGS) AM_CXXFLAGS = $(common_cflags) $(M_CXXFLAGS) $(CXXFLAGS) +EXTRA_DIST = \ + $(widget_sources) \ + $(widget_unix_sources) \ + $(widget_win32_sources) + + +############################################################################ +# UNIX +# +if UNIX_BUILD + noinst_LTLIBRARIES = libmooterm.la -libmooterm_la_SOURCES = $(widget_sources) +libmooterm_la_SOURCES = $(widget_sources) $(widget_unix_sources) + +endif UNIX_BUILD + + +############################################################################ +# MINGW +# +if MINGW_BUILD + +noinst_LTLIBRARIES = libmooterm.la + +libmooterm_la_SOURCES = $(widget_sources) $(widget_win32_sources) + +endif MINGW_BUILD + + +############################################################################ +# CYGWIN +# +if CYGWIN_BUILD + +noinst_PROGRAMS = termhelper + +termhelper_CFLAGS = \ + $(AM_CFLAGS) \ + $(CYGWIN_CFLAGS) + +termhelper_SOURCES = $(termhelper_sources) +termhelper_LDADD = $(CYGWIN_LDFLAGS) termhelper_res.res + +termhelper_res.res: termhelper_res.rc + $(WINDRES) -i termhelper_res.rc --input-format=rc -o termhelper_res.res -O coff + +endif CYGWIN_BUILD diff --git a/moo/mooterm/mooterm.c b/moo/mooterm/mooterm.c index 7d36604b..0700ab6b 100644 --- a/moo/mooterm/mooterm.c +++ b/moo/mooterm/mooterm.c @@ -649,3 +649,15 @@ void moo_term_size_changed (MooTerm *term) moo_term_buffer_set_screen_size (term->priv->buffer, width, height); moo_term_vt_set_size (term->priv->vt, width, height); } + + +gboolean moo_term_fork_command (MooTerm *term, + const char *cmd, + const char *working_dir, + char **envp) +{ + g_return_val_if_fail (MOO_IS_TERM (term), FALSE); + + return moo_term_vt_fork_command (term->priv->vt, + cmd, working_dir, envp); +} diff --git a/moo/mooterm/mooterm.h b/moo/mooterm/mooterm.h index 06940334..ff426ce6 100644 --- a/moo/mooterm/mooterm.h +++ b/moo/mooterm/mooterm.h @@ -56,6 +56,11 @@ MooTermBuffer *moo_term_get_buffer (MooTerm *term); void moo_term_set_adjustment (MooTerm *term, GtkAdjustment *vadj); +gboolean moo_term_fork_command (MooTerm *term, + const char *cmd, + const char *working_dir, + char **envp); + G_END_DECLS diff --git a/moo/mooterm/mootermvt-unix.c b/moo/mooterm/mootermvt-unix.c new file mode 100644 index 00000000..e5405459 --- /dev/null +++ b/moo/mooterm/mootermvt-unix.c @@ -0,0 +1,499 @@ +/* + * mooterm/mootermvt-unix.c + * + * Copyright (C) 2004-2005 by Yevgen Muntyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * See COPYING file that comes with this distribution. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mooterm/mootermvt.h" +#include "mooterm/pty.h" +#include "mooutils/moomarshals.h" +#include "mooutils/moocompat.h" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_POLL_H +#include +#elif HAVE_SYS_POLL_H +#include +#endif + + +#define TERM_EMULATION "xterm" +#define READ_BUFSIZE 4096 +#define POLL_TIME 5 +#define POLL_NUM 1 + + +#define MOO_TERM_VT_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOO_TYPE_TERM_VT_UNIX, MooTermVtUnix)) +#define MOO_TERM_VT_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TERM_VT_UNIX, MooTermVtUnixClass)) +#define MOO_IS_TERM_VT_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOO_TYPE_TERM_VT_UNIX)) +#define MOO_IS_TERM_VT_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_TERM_VT_UNIX)) +#define MOO_TERM_VT_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_TERM_VT_UNIX, MooTermVtUnixClass)) + +typedef struct _MooTermVtUnix MooTermVtUnix; +typedef struct _MooTermVtUnixClass MooTermVtUnixClass; + + +struct _MooTermVtUnix { + MooTermVt parent; + + gboolean child_alive; + GPid child_pid; + + int master; + int width; + int height; + + GIOChannel *io; + guint io_watch_id; +}; + + +struct _MooTermVtUnixClass { + MooTermVtClass parent_class; +}; + + +static void moo_term_vt_unix_finalize (GObject *object); + +static void set_size (MooTermVt *vt, + gulong width, + gulong height); +static gboolean fork_command (MooTermVt *vt, + const char *cmd, + const char *working_dir, + char **envp); +static void feed_child (MooTermVt *vt, + const char *string, + gssize len); +static void kill_child (MooTermVt *vt); + +static gboolean read_child_out (GIOChannel *source, + GIOCondition condition, + MooTermVtUnix *vt); +static void feed_parent (MooTermVtUnix *vt, + const char *string, + gssize len); + + +/* MOO_TYPE_TERM_VT_UNIX */ +G_DEFINE_TYPE (MooTermVtUnix, moo_term_vt_unix, MOO_TYPE_TERM_VT) + + +static void moo_term_vt_unix_class_init (MooTermVtUnixClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + MooTermVtClass *vt_class = MOO_TERM_VT_CLASS (klass); + + gobject_class->finalize = moo_term_vt_unix_finalize; + + vt_class->set_size = set_size; + vt_class->fork_command = fork_command; + vt_class->feed_child = feed_child; + vt_class->kill_child = kill_child; +} + + +static void moo_term_vt_unix_init (MooTermVtUnix *vt) +{ + vt->child_alive = FALSE; + vt->child_pid = (GPid)-1; + + vt->master = -1; + vt->width = 80; + vt->height = 24; + + vt->io = NULL; + vt->io_watch_id = 0; +} + + +static void moo_term_vt_unix_finalize (GObject *object) +{ + MooTermVtUnix *vt = MOO_TERM_VT_UNIX (object); + kill_child (MOO_TERM_VT (vt)); + G_OBJECT_CLASS (moo_term_vt_unix_parent_class)->finalize (object); +} + + +static void set_size (MooTermVt *vt, + gulong width, + gulong height) +{ + MooTermVtUnix *vtu; + + g_return_if_fail (MOO_IS_TERM_VT_UNIX (vt)); + + vtu = MOO_TERM_VT_UNIX (vt); + + if (vtu->child_alive) + _vte_pty_set_size (vtu->master, width, height); + + vtu->width = width; + vtu->height = height; +} + + +static gboolean fork_command (MooTermVt *vt_gen, + const char *cmd, + const char *working_dir, + char **envp) +{ + MooTermVtUnix *vt; + int argv_len; + char **argv = NULL; + int env_len = 0; + char **new_env; + GError *err = NULL; + int status, flags; + int i; + + g_return_val_if_fail (cmd != NULL, FALSE); + g_return_val_if_fail (MOO_IS_TERM_VT_UNIX (vt_gen), FALSE); + + vt = MOO_TERM_VT_UNIX (vt_gen); + + g_return_val_if_fail (!vt->child_alive, FALSE); + + if (!g_shell_parse_argv (cmd, &argv_len, &argv, &err)) + { + g_critical ("%s: could not parse command line", G_STRLOC); + + if (err != NULL) + { + g_critical ("%s: %s", G_STRLOC, err->message); + g_error_free (err); + } + + if (argv != NULL) + g_strfreev (argv); + + return FALSE; + } + + if (envp) + { + char **e; + for (e = envp; *e != NULL; ++e) + ++env_len; + } + + new_env = g_new (char*, env_len + 2); + + for (i = 0; i < env_len; ++i) + new_env[i] = g_strdup (envp[i]); + + new_env[env_len] = g_strdup ("TERM=" TERM_EMULATION); + new_env[env_len + 1] = NULL; + + vt->master = _vte_pty_open (&vt->child_pid, new_env, + argv[0], + argv, + working_dir, + vt->width, vt->height, + FALSE, FALSE, FALSE); + g_strfreev (new_env); + + if (vt->master == -1) + { + g_critical ("%s: could not fork child", G_STRLOC); + return FALSE; + } + else + { + g_message ("%s: forked child pid %d", G_STRLOC, vt->child_pid); + } + + if (waitpid (-1, &status, WNOHANG) == -1) + g_critical ("%s: error in waitpid", G_STRLOC); + + if ((flags = fcntl (vt->master, F_GETFL)) < 0) + g_critical ("%s: F_GETFL on master", G_STRLOC); + else if (-1 == fcntl (vt->master, F_SETFL, O_NONBLOCK | flags)) + g_critical ("%s: F_SETFL on master", G_STRLOC); + + vt->io = g_io_channel_unix_new (vt->master); + g_return_val_if_fail (vt->io != NULL, FALSE); + + g_io_channel_set_encoding (vt->io, NULL, NULL); + g_io_channel_set_buffered (vt->io, FALSE); + + vt->io_watch_id = g_io_add_watch (vt->io, + G_IO_IN | G_IO_PRI | G_IO_HUP, + (GIOFunc) read_child_out, + vt); + +#if 0 +// GSource *src = g_main_context_find_source_by_id (NULL, helper_out_watch_id); +// if (src) g_source_set_priority (src, READ_HELPER_OUT_PRIORITY); +// else g_warning ("%s: could not find helper_io_watch source", G_STRLOC); +#endif + + vt->child_alive = TRUE; + + return TRUE; +} + + +static void kill_child (MooTermVt *vt_gen) +{ + MooTermVtUnix *vt = MOO_TERM_VT_UNIX (vt_gen); + + if (vt->io_watch_id) + { + g_source_remove (vt->io_watch_id); + vt->io_watch_id = 0; + } + + if (vt->io) + { + feed_child (MOO_TERM_VT (vt), "\4", 1); + g_io_channel_shutdown (vt->io, TRUE, NULL); + g_io_channel_unref (vt->io); + vt->io = NULL; + } + + if (vt->master != -1) + { + _vte_pty_close (vt->master); + vt->master = -1; + } + + vt->child_pid = (GPid)-1; + + if (vt->child_alive) + { + vt->child_alive = FALSE; + g_signal_emit_by_name (vt, "child-died"); + } +} + + +static gboolean read_child_out (G_GNUC_UNUSED GIOChannel *source, + GIOCondition condition, + MooTermVtUnix *vt) +{ + gboolean error_occured = FALSE; + int error_no = 0; + + char buf[READ_BUFSIZE]; + int current = 0; + guint again = POLL_NUM; + + if (condition & G_IO_HUP) + { + g_message ("%s: G_IO_HUP", G_STRLOC); + error_no = errno; + goto error; + } + else if (condition & G_IO_ERR) + { + g_message ("%s: G_IO_ERR", G_STRLOC); + error_no = errno; + goto error; + } + + g_assert (condition & (G_IO_IN | G_IO_PRI)); + + while (again && !error_occured && current < READ_BUFSIZE) + { + struct pollfd fd = {vt->master, POLLIN | POLLPRI, 0}; + + int res = poll (&fd, 1, POLL_TIME); + + switch (res) + { + case 0: + --again; + break; + + case 1: + if (fd.revents & (POLLNVAL | POLLERR | POLLHUP)) + { + again = 0; + if (errno != EAGAIN && errno != EINTR) + { + error_occured = TRUE; + error_no = errno; + } + } + else if (fd.revents & (POLLIN | POLLPRI)) + { + int r = read (vt->master, buf + current, 1); + + switch (r) + { + case -1: + error_occured = TRUE; + error_no = errno; + break; + + case 0: + --again; + break; + + case 1: + ++current; + break; + + default: + g_assert_not_reached(); + } + } + + break; + + case -1: + again = 0; + + if (errno != EAGAIN && errno != EINTR) + { + error_occured = TRUE; + error_no = errno; + } + + break; + + default: + g_assert_not_reached(); + } + } + + if (current > 0) + feed_parent (vt, buf, current); + + if (error_occured) + goto error; + + return TRUE; + +error: + if (error_occured) + g_message ("error in %s", G_STRLOC); + + if (error_no) + g_message ("%s: %s", G_STRLOC, g_strerror (error_no)); + + if (vt->io) + { + _vte_pty_close (vt->master); + vt->master = -1; + + g_io_channel_shutdown (vt->io, TRUE, NULL); + g_io_channel_unref (vt->io); + vt->io = NULL; + + vt->io_watch_id = 0; + } + + kill_child (MOO_TERM_VT (vt)); + + return FALSE; +} + + +static void feed_parent (MooTermVtUnix *vt, + const char *string, + gssize len) +{ + moo_term_buffer_feed (moo_term_vt_get_buffer (MOO_TERM_VT (vt)), + string, len); +} + + +#define CHUNK_SIZE 1024 + +static void feed_child (MooTermVt *vt_gen, + const char *string, + gssize len) +{ + guint total_written = 0; + GError *err = NULL; + guint eagain_count = 0; + + MooTermVtUnix *vt = MOO_TERM_VT_UNIX (vt_gen); + + g_return_if_fail (vt->io != NULL); + + if (len < 0) + len = strlen (string); + + while (total_written < (guint)len) + { + gsize written = 0; + GIOStatus status; + + status = g_io_channel_write_chars (vt->io, string + total_written, + MIN (len - total_written, CHUNK_SIZE), + &written, &err); + + if (err) + { + g_critical ("%s: %s", G_STRLOC, err->message); + g_error_free (err); + break; + } + + if (status != G_IO_STATUS_NORMAL) + { + gboolean stop = FALSE; + + switch (status) + { + case G_IO_STATUS_ERROR: + g_critical ("%s: g_io_channel_write_chars returned G_IO_STATUS_ERROR", G_STRLOC); + stop = TRUE; + break; + + case G_IO_STATUS_EOF: + g_critical ("%s: g_io_channel_write_chars returned G_IO_STATUS_EOF", G_STRLOC); + stop = TRUE; + break; + + case G_IO_STATUS_AGAIN: + ++eagain_count; + + if (eagain_count > 2) + { + g_critical ("%s: g_io_channel_write_chars returned G_IO_STATUS_AGAIN 2 times", G_STRLOC); + stop = TRUE; + } + else + { + g_usleep (10000); + } + + break; + + default: + g_assert_not_reached (); + } + + if (stop) + break; + } + else if (written <= 0) + { + g_critical ("%s: error in g_io_channel_write_chars", G_STRLOC); + break; + } + + total_written += written; + } +} diff --git a/moo/mooterm/mootermvt-win32.c b/moo/mooterm/mootermvt-win32.c new file mode 100644 index 00000000..6e2a1880 --- /dev/null +++ b/moo/mooterm/mootermvt-win32.c @@ -0,0 +1,16 @@ +/* + * mooterm/mootermvt-win32.c + * + * Copyright (C) 2004-2005 by Yevgen Muntyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * See COPYING file that comes with this distribution. + */ + +#include "mooterm/mootermvt.h" + + diff --git a/moo/mooterm/mootermvt.c b/moo/mooterm/mootermvt.c index e0f58a51..c76a2ef5 100644 --- a/moo/mooterm/mootermvt.c +++ b/moo/mooterm/mootermvt.c @@ -12,6 +12,8 @@ */ #include "mooterm/mootermvt.h" +#include "mooutils/moomarshals.h" +#include "mooutils/moocompat.h" struct _MooTermVtPrivate { @@ -34,6 +36,7 @@ static void moo_term_vt_finalize (GObject *object); G_DEFINE_TYPE (MooTermVt, moo_term_vt, G_TYPE_OBJECT) enum { + CHILD_DIED, LAST_SIGNAL }; @@ -42,7 +45,7 @@ enum { PROP_BUFFER }; -// static guint signals[LAST_SIGNAL]; +static guint signals[LAST_SIGNAL]; static void moo_term_vt_class_init (MooTermVtClass *klass) @@ -53,6 +56,21 @@ static void moo_term_vt_class_init (MooTermVtClass *klass) gobject_class->get_property = moo_term_vt_get_property; gobject_class->finalize = moo_term_vt_finalize; + klass->set_size = NULL; + klass->fork_command = NULL; + klass->feed_child = NULL; + klass->kill_child = NULL; + klass->child_died = NULL; + + signals[CHILD_DIED] = + g_signal_new ("child-died", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MooTermVtClass, child_died), + NULL, NULL, + _moo_marshal_VOID__VOID, + G_TYPE_NONE, 0); + g_object_class_install_property (gobject_class, PROP_BUFFER, g_param_spec_object ("buffer", @@ -143,13 +161,44 @@ MooTermBuffer *moo_term_vt_get_buffer (MooTermVt *vt) MooTermVt *moo_term_vt_new (void) { - return MOO_TERM_VT (g_object_new (MOO_TYPE_TERM_VT, NULL)); +#ifdef __WIN32__ + return g_object_new (MOO_TYPE_TERM_VT_WIN, NULL); +#else /* !__WIN32__ */ + return g_object_new (MOO_TYPE_TERM_VT_UNIX, NULL); +#endif /* !__WIN32__ */ } -void moo_term_vt_set_size (G_GNUC_UNUSED MooTermVt *vt, - G_GNUC_UNUSED gulong width, - G_GNUC_UNUSED gulong height) +void moo_term_vt_set_size (MooTermVt *vt, + gulong width, + gulong height) { -// g_message ("%s: implement me", G_STRLOC); + g_return_if_fail (MOO_IS_TERM_VT (vt)); + MOO_TERM_VT_GET_CLASS(vt)->set_size (vt, width, height); +} + + +gboolean moo_term_vt_fork_command (MooTermVt *vt, + const char *cmd, + const char *working_dir, + char **envp) +{ + g_return_val_if_fail (MOO_IS_TERM_VT (vt), FALSE); + return MOO_TERM_VT_GET_CLASS(vt)->fork_command (vt, cmd, working_dir, envp); +} + + +void moo_term_vt_kill_child (MooTermVt *vt) +{ + g_return_if_fail (MOO_IS_TERM_VT (vt)); + MOO_TERM_VT_GET_CLASS(vt)->kill_child (vt); +} + + +void moo_term_vt_feed_child (MooTermVt *vt, + const char *data, + gssize len) +{ + g_return_if_fail (MOO_IS_TERM_VT (vt)); + MOO_TERM_VT_GET_CLASS(vt)->feed_child (vt, data, len); } diff --git a/moo/mooterm/mootermvt.h b/moo/mooterm/mootermvt.h index 7ed47f70..536af207 100644 --- a/moo/mooterm/mootermvt.h +++ b/moo/mooterm/mootermvt.h @@ -20,6 +20,9 @@ G_BEGIN_DECLS #define MOO_TYPE_TERM_VT (moo_term_vt_get_type ()) +#define MOO_TYPE_TERM_VT_WIN (moo_term_vt_win_get_type ()) +#define MOO_TYPE_TERM_VT_UNIX (moo_term_vt_unix_get_type ()) + #define MOO_TERM_VT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOO_TYPE_TERM_VT, MooTermVt)) #define MOO_TERM_VT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TERM_VT, MooTermVtClass)) #define MOO_IS_TERM_VT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOO_TYPE_TERM_VT)) @@ -38,19 +41,49 @@ struct _MooTermVt { struct _MooTermVtClass { GObjectClass parent_class; + + /* virtual methods */ + void (*set_size) (MooTermVt *vt, + gulong width, + gulong height); + gboolean (*fork_command) (MooTermVt *vt, + const char *cmd, + const char *working_dir, + char **envp); + void (*feed_child) (MooTermVt *vt, + const char *data, + gssize len); + void (*kill_child) (MooTermVt *vt); + + /* signals */ + void (*child_died) (MooTermVt *vt); }; -GType moo_term_vt_get_type (void) G_GNUC_CONST; +GType moo_term_vt_get_type (void) G_GNUC_CONST; +GType moo_term_vt_unix_get_type (void) G_GNUC_CONST; +GType moo_term_vt_win_get_type (void) G_GNUC_CONST; -MooTermVt *moo_term_vt_new (void); -void moo_term_vt_set_size (MooTermVt *vt, - gulong width, - gulong height); +/* creates MooTermVtWin or MooTermVtUnix instance, depending on platform */ +MooTermVt *moo_term_vt_new (void); -void moo_term_vt_set_buffer (MooTermVt *vt, - MooTermBuffer *buffer); -MooTermBuffer *moo_term_vt_get_buffer (MooTermVt *vt); +void moo_term_vt_set_buffer (MooTermVt *vt, + MooTermBuffer *buffer); +MooTermBuffer *moo_term_vt_get_buffer (MooTermVt *vt); + +void moo_term_vt_set_size (MooTermVt *vt, + gulong width, + gulong height); + +gboolean moo_term_vt_fork_command (MooTermVt *vt, + const char *cmd, + const char *working_dir, + char **envp); +void moo_term_vt_kill_child (MooTermVt *vt); + +void moo_term_vt_feed_child (MooTermVt *vt, + const char *data, + gssize len); G_END_DECLS diff --git a/tests/Makefile.am b/tests/Makefile.am index dcb7c228..d5cbc39f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2,7 +2,7 @@ # tests/Makefile.am # -EXTRA_PROGRAMS = medit mterm markup editor +EXTRA_PROGRAMS = medit mterm markup editor termbuffer noinst_PROGRAMS = EXTRA_DIST = pyapp.py.in @@ -15,7 +15,7 @@ if BUILD_MOOEDIT noinst_PROGRAMS += medit endif if BUILD_MOOTERM -noinst_PROGRAMS += mterm +noinst_PROGRAMS += mterm termbuffer endif if BUILD_MOOUTILS noinst_PROGRAMS += markup @@ -74,14 +74,17 @@ medit_SOURCES = medit.cpp ## mterm_LDFLAGS = mterm_LDADD = $(MOO_LIBS) ../moo/libmoo.la +termbuffer_LDADD = $(mterm_LDADD) if MINGW_BUILD mterm_LDFLAGS += -mwindows endif MINGW_BUILD -mterm_SOURCES = \ - mterm.cpp +termbuffer_LDFLAGS = $(mterm_LDFLAGS) + +mterm_SOURCES = mterm.cpp +termbuffer_SOURCES = termbuffer.cpp ############################################################################## diff --git a/tests/mterm.cpp b/tests/mterm.cpp index 650b9e58..549d6d86 100644 --- a/tests/mterm.cpp +++ b/tests/mterm.cpp @@ -17,89 +17,26 @@ #include #include -#ifndef __WIN32__ -#define CMD "sh" -#else -#define CMD "gapw95.exe" -#endif - -#define CLEAR "\033[H\033[2J" -#define HOME "\033[H" -#define PARM_RIGHT "\033[%dC" -#define PARM_LEFT "\033[%dD" -#define ADDRESS "\033[%d;%dH" - -#define GREEN "\033[0;40;32m" -#define NORMAL "\033[0m" - - -bool print (MooTermBuffer *buf) -{ - for (guint i = 0; i < 1000; ++i) - moo_term_buffer_feed (buf, "kjhr jerhgjh erkjg hekrjghkerg ", -1); - return false; -} - - -bool print_random_hard (MooTerm *term) -{ - MooTermBuffer *buf = term->priv->buffer; - guint width = buf_screen_width (buf); - guint height = buf_screen_height (buf); - guint row, col; - gboolean first_time = TRUE; - - for (guint i = 0; i < 10000; ++i) - { - char r = 32 + (int) (94.0 * rand() / (RAND_MAX+1.0)); - row = 1 + (int) (((double)height) * rand() / (RAND_MAX+1.0)); - col = 1 + (int) (((double)width) * rand() / (RAND_MAX+1.0)); - - char *s = g_strdup_printf (ADDRESS "%c", row, col, r); - moo_term_buffer_feed (buf, s, -1); - g_free (s); - - moo_term_force_update (term); - } - - g_print ("buffer: %dx%d\nterm: %dx%d\n", - buf_total_height (buf), buf_screen_width (buf), - term_height (term), term_width (term)); - - gtk_main_quit (); - return false; -} - - -bool print_random_soft (MooTerm *term) -{ - MooTermBuffer *buf = term->priv->buffer; - guint width = buf_screen_width (buf); - guint height = buf_screen_height (buf); - guint row, col; - gboolean first_time = TRUE; - - char r = 32 + (int) (94.0 * rand() / (RAND_MAX+1.0)); - row = 1 + (int) (((double)height) * rand() / (RAND_MAX+1.0)); - col = 1 + (int) (((double)width) * rand() / (RAND_MAX+1.0)); - - char *s = g_strdup_printf (ADDRESS "%c", row, col, r); - moo_term_buffer_feed (buf, s, -1); - g_free (s); - - return true; -} - - int main (int argc, char *argv[]) { gtk_init (&argc, &argv); - const char *cmd = CMD; - if (argc > 1) cmd = argv[1]; + char *cmd = NULL; + + if (argc > 1) + { + cmd = g_strdup (argv[1]); + } + else + { + const char *dir = g_getenv ("HOME"); + if (!dir) + dir = "/"; + cmd = g_strdup_printf ("ls -R %s", dir); + } GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_widget_set_size_request (win, 400, 400); + gtk_window_set_default_size (GTK_WINDOW (win), 400, 400); GtkWidget *swin = gtk_scrolled_window_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (win), swin); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), @@ -113,17 +50,13 @@ int main (int argc, char *argv[]) MooTermBuffer *buf = moo_term_get_buffer (MOO_TERM (term)); g_object_set (buf, - "am-mode", FALSE, - "insert-mode", FALSE, + "am-mode", TRUE, + "insert-mode", TRUE, "cursor-visible", TRUE, NULL); -// for (guint i = 0; i < 1000; ++i) -// moo_term_buffer_feed (buf, "Hello there", -1); -// g_print ("%dx%d\n", buf_screen_width (buf), buf_total_height (buf)); - -// g_timeout_add (1000, (GSourceFunc) print, buf); - g_idle_add ((GSourceFunc) print_random_hard, term); + moo_term_fork_command (MOO_TERM (term), cmd, NULL, NULL); + g_free (cmd); g_signal_connect (G_OBJECT (win), "destroy", gtk_main_quit, NULL); gtk_main (); diff --git a/tests/termbuffer.cpp b/tests/termbuffer.cpp new file mode 100644 index 00000000..650b9e58 --- /dev/null +++ b/tests/termbuffer.cpp @@ -0,0 +1,130 @@ +// +// tests/mterm.cpp +// +// Copyright (C) 2004-2005 by Yevgen Muntyan +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// See COPYING file that comes with this distribution. +// + +#include +#define MOOTERM_COMPILATION +#include "mooterm/mooterm-private.h" +#include +#include + +#ifndef __WIN32__ +#define CMD "sh" +#else +#define CMD "gapw95.exe" +#endif + +#define CLEAR "\033[H\033[2J" +#define HOME "\033[H" +#define PARM_RIGHT "\033[%dC" +#define PARM_LEFT "\033[%dD" +#define ADDRESS "\033[%d;%dH" + +#define GREEN "\033[0;40;32m" +#define NORMAL "\033[0m" + + +bool print (MooTermBuffer *buf) +{ + for (guint i = 0; i < 1000; ++i) + moo_term_buffer_feed (buf, "kjhr jerhgjh erkjg hekrjghkerg ", -1); + return false; +} + + +bool print_random_hard (MooTerm *term) +{ + MooTermBuffer *buf = term->priv->buffer; + guint width = buf_screen_width (buf); + guint height = buf_screen_height (buf); + guint row, col; + gboolean first_time = TRUE; + + for (guint i = 0; i < 10000; ++i) + { + char r = 32 + (int) (94.0 * rand() / (RAND_MAX+1.0)); + row = 1 + (int) (((double)height) * rand() / (RAND_MAX+1.0)); + col = 1 + (int) (((double)width) * rand() / (RAND_MAX+1.0)); + + char *s = g_strdup_printf (ADDRESS "%c", row, col, r); + moo_term_buffer_feed (buf, s, -1); + g_free (s); + + moo_term_force_update (term); + } + + g_print ("buffer: %dx%d\nterm: %dx%d\n", + buf_total_height (buf), buf_screen_width (buf), + term_height (term), term_width (term)); + + gtk_main_quit (); + return false; +} + + +bool print_random_soft (MooTerm *term) +{ + MooTermBuffer *buf = term->priv->buffer; + guint width = buf_screen_width (buf); + guint height = buf_screen_height (buf); + guint row, col; + gboolean first_time = TRUE; + + char r = 32 + (int) (94.0 * rand() / (RAND_MAX+1.0)); + row = 1 + (int) (((double)height) * rand() / (RAND_MAX+1.0)); + col = 1 + (int) (((double)width) * rand() / (RAND_MAX+1.0)); + + char *s = g_strdup_printf (ADDRESS "%c", row, col, r); + moo_term_buffer_feed (buf, s, -1); + g_free (s); + + return true; +} + + +int main (int argc, char *argv[]) +{ + gtk_init (&argc, &argv); + + const char *cmd = CMD; + if (argc > 1) cmd = argv[1]; + + GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request (win, 400, 400); + GtkWidget *swin = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (win), swin); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + + GtkWidget *term = GTK_WIDGET (g_object_new (MOO_TYPE_TERM, NULL)); + gtk_container_add (GTK_CONTAINER (swin), term); + + gtk_widget_show_all (win); + + MooTermBuffer *buf = moo_term_get_buffer (MOO_TERM (term)); + g_object_set (buf, + "am-mode", FALSE, + "insert-mode", FALSE, + "cursor-visible", TRUE, + NULL); + +// for (guint i = 0; i < 1000; ++i) +// moo_term_buffer_feed (buf, "Hello there", -1); +// g_print ("%dx%d\n", buf_screen_width (buf), buf_total_height (buf)); + +// g_timeout_add (1000, (GSourceFunc) print, buf); + g_idle_add ((GSourceFunc) print_random_hard, term); + + g_signal_connect (G_OBJECT (win), "destroy", gtk_main_quit, NULL); + gtk_main (); +}