Added MooTermPtWin, MooTermPt class for spawning any windows applications.

Sorted out MooTermPt stuff a bit; made sen_intr and get_erase_char virtual methods;
made MooTermPtCyg subclass MooTermPtWin.
Started mterm-app.
master
Yevgen Muntyan 2006-04-03 02:56:05 -05:00
parent d1f8889eaf
commit 84e7bd1fe8
14 changed files with 2697 additions and 675 deletions

View File

@ -15,9 +15,19 @@ depcomp
install-sh
ltmain\.sh
missing
.*\.o
.*\.exe
devcpp.*_private\.*
devcpp.*\.ico
devcpp.*Makefile\.win
devcpp.*\.layout
.*\.pyc
.*~
.*\.pcs
.*\.kdevses
.*\.gladep
.*\.bak
.*-glade\.h
moomarshals\.[ch]
pcre\.h
tests.*-ui\.h

62
devcpp/mterm-before.mak Normal file
View File

@ -0,0 +1,62 @@
MOO = ../moo
MOO_W = ..\moo
XML2H = $(MOO)/mooutils/xml2h.py
mooutils = $(MOO)/mooutils
mooutils_srcdir = $(MOO)/mooutils
tests = ../tests
GENERATED = \
config.h \
$(mooutils)/pcre/pcre.h \
$(mooutils)/moomarshals.h \
$(mooutils)/moomarshals.c \
$(mooutils)/mooaccelbutton-glade.h \
$(mooutils)/mooaccelprefs-glade.h \
$(MOO)/mooterm/mootermprefs-glade.h \
$(tests)/mterm-ui.h \
$(tests)/medit-ui.h
all-before: $(GENERATED)
##############################################################
# Marshalers
#
$(MOO)/mooutils/moomarshals.h: $(MOO)/mooutils/moomarshals.list
glib-genmarshal --prefix=_moo_marshal --header $(MOO)/mooutils/moomarshals.list > $(MOO)/mooutils/moomarshals.h
$(MOO)/mooutils/moomarshals.c: $(MOO)/mooutils/moomarshals.list
glib-genmarshal --prefix=_moo_marshal --body $(MOO)/mooutils/moomarshals.list > $(MOO)/mooutils/moomarshals.c
##############################################################
# config.h
#
$(MOO)/mooutils/pcre/pcre.h: $(MOO)/mooutils/pcre/pcre.h.win32
copy /Y $(MOO_W)\mooutils\pcre\pcre.h.win32 $(MOO_W)\mooutils\pcre\pcre.h
config.h: ../config.h.win32
copy /Y ..\config.h.win32 config.h
##############################################################
# glade files
#
$(MOO)/mooterm/mootermprefs-glade.h: $(MOO)/mooterm/glade/mootermprefs.glade $(XML2H)
python $(XML2H) MOO_TERM_PREFS_GLADE_UI $(MOO)/mooterm/glade/mootermprefs.glade \
> $(MOO)/mooterm/mootermprefs-glade.h
$(mooutils)/mooaccelbutton-glade.h: $(mooutils_srcdir)/glade/shortcutdialog.glade $(XML2H)
python $(XML2H) MOO_ACCEL_BUTTON_GLADE_UI \
$(mooutils_srcdir)/glade/shortcutdialog.glade > $(mooutils)/mooaccelbutton-glade.h
$(mooutils)/mooaccelprefs-glade.h: $(mooutils_srcdir)/glade/shortcutsprefs.glade $(XML2H)
python $(XML2H) MOO_SHORTCUTS_PREFS_GLADE_UI \
$(mooutils_srcdir)/glade/shortcutsprefs.glade > $(mooutils)/mooaccelprefs-glade.h
##############################################################
# xml
#
$(tests)/medit-ui.h: $(tests)/medit-ui.xml $(XML2H)
python $(XML2H) MEDIT_UI $(tests)/medit-ui.xml > $(tests)/medit-ui.h
$(tests)/mterm-ui.h: $(tests)/mterm-ui.xml $(XML2H)
python $(XML2H) MTERM_UI $(tests)/mterm-ui.xml > $(tests)/mterm-ui.h

1529
devcpp/mterm.dev Normal file

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,8 @@ mooterm_unix_sources = \
mooterm_win32_sources = \
$(mooterm)/mootermhelper.h \
$(mooterm)/mootermpt-cygwin.c
$(mooterm)/mootermpt-cygwin.c \
$(mooterm)/mootermpt-win32.c
termhelper_sources = \
termhelper_res.res \

View File

@ -13,6 +13,7 @@
#define MOOTERM_COMPILATION
#include "mooterm/mootermpt-private.h"
#include "mooterm/mootermpt-win32.h"
#include "mooterm/mooterm-private.h"
#include "mooterm/mootermhelper.h"
#include "mooterm/mooterm-private.h"
@ -47,40 +48,27 @@ void moo_term_set_helper_directory (const char *dir)
#define TERM_HEIGHT(pt__) (MOO_TERM_PT(pt__)->priv->term->priv->height)
#define MOO_TERM_PT_WIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOO_TYPE_TERM_PT_WIN, MooTermPtCyg))
#define MOO_TERM_PT_WIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TERM_PT_WIN, MooTermPtCygClass))
#define MOO_IS_TERM_PT_WIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOO_TYPE_TERM_PT_WIN))
#define MOO_IS_TERM_PT_WIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_TERM_PT_WIN))
#define MOO_TERM_PT_WIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_TERM_PT_WIN, MooTermPtCygClass))
#define MOO_TERM_PT_CYG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOO_TYPE_TERM_PT_CYG, MooTermPtCyg))
#define MOO_TERM_PT_CYG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TERM_PT_CYG, MooTermPtCygClass))
#define MOO_IS_TERM_PT_CYG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOO_TYPE_TERM_PT_CYG))
#define MOO_IS_TERM_PT_CYG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_TERM_PT_CYG))
#define MOO_TERM_PT_CYG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_TERM_PT_CYG, MooTermPtCygClass))
typedef struct _MooTermPtCyg MooTermPtCyg;
typedef struct _MooTermPtCygClass MooTermPtCygClass;
struct _MooTermPtCyg {
MooTermPt parent;
GPid pid;
gulong process_id;
int in;
int out;
GIOChannel *in_io;
GIOChannel *out_io;
guint watch_id;
guint out_watch_id;
MooTermPtWin parent;
};
struct _MooTermPtCygClass {
MooTermPtClass parent_class;
MooTermPtWinClass parent_class;
};
static void moo_term_pt_cyg_finalize (GObject *object);
static gboolean read_helper_out (GIOChannel *source,
GIOCondition condition,
MooTermPtCyg *self);
static void set_size (MooTermPt *pt,
guint width,
guint height);
@ -89,22 +77,13 @@ static gboolean fork_command (MooTermPt *pt,
const char *working_dir,
char **envp,
GError **error);
static void pt_write (MooTermPt *pt,
const char *string,
gssize len);
static void kill_child (MooTermPt *pt);
static gboolean run_in_helper (const char *cmd,
const char *working_dir,
char **env,
guint width, guint height,
int *hin, int *hout,
GPid *hpid, gulong *hproc_id,
GError **error);
static char get_erase_char (MooTermPt *pt);
static void send_intr (MooTermPt *pt);
/* MOO_TYPE_TERM_PT_WIN */
G_DEFINE_TYPE (MooTermPtCyg, moo_term_pt_cyg, MOO_TYPE_TERM_PT)
/* MOO_TYPE_TERM_PT_CYG */
G_DEFINE_TYPE (MooTermPtCyg, moo_term_pt_cyg, MOO_TYPE_TERM_PT_WIN)
static void
@ -117,43 +96,25 @@ moo_term_pt_cyg_class_init (MooTermPtCygClass *klass)
pt_class->set_size = set_size;
pt_class->fork_command = fork_command;
pt_class->write = pt_write;
pt_class->kill_child = kill_child;
pt_class->send_intr = send_intr;
pt_class->get_erase_char = get_erase_char;
}
static void
moo_term_pt_cyg_init (MooTermPtCyg *pt)
{
MOO_TERM_PT(pt)->priv->child_alive = FALSE;
pt->pid = (GPid) -1;
pt->process_id = 0;
pt->watch_id = 0;
pt->in = -1;
pt->in_io = NULL;
pt->out = -1;
pt->out_io = NULL;
pt->out_watch_id = 0;
}
static void
moo_term_pt_cyg_finalize (GObject *object)
moo_term_pt_cyg_finalize (GObject *object)
{
MooTermPtCyg *pt = MOO_TERM_PT_WIN (object);
kill_child (MOO_TERM_PT (pt));
G_OBJECT_CLASS (moo_term_pt_cyg_parent_class)->finalize (object);
}
MooTermCommand *
_moo_term_get_default_shell (void)
{
g_return_val_if_reached (NULL);
}
static gboolean
fork_command (MooTermPt *pt_gen,
const MooTermCommand *cmd,
@ -163,422 +124,15 @@ fork_command (MooTermPt *pt_gen,
{
MooTermPtCyg *pt;
gboolean result;
char *cmd_line = NULL;
GString *helper_binary = NULL;
char *old_path;
MooTermCommand *new_cmd;
g_return_val_if_fail (!pt_gen->priv->child_alive, FALSE);
g_return_val_if_fail (cmd->cmd_line != NULL, FALSE);
pt = MOO_TERM_PT_WIN (pt_gen);
result = run_in_helper (cmd->cmd_line, working_dir, envp,
TERM_WIDTH (pt), TERM_HEIGHT (pt),
&pt->in, &pt->out, &pt->pid,
&pt->process_id, error);
if (!result)
return FALSE;
else
g_message ("%s: started helper pid %d", G_STRLOC,
(int) pt->pid);
pt->in_io = g_io_channel_win32_new_fd (pt->in);
g_io_channel_set_encoding (pt->in_io, NULL, NULL);
// pt->priv->in_watch_id = g_io_add_watch (pt->priv->in_io,
// (GIOCondition)(G_IO_ERR | G_IO_HUP),
// (GIOFunc)helper_in_hup,
// pt);
pt->out_io = g_io_channel_win32_new_fd (pt->out);
g_io_channel_set_encoding (pt->out_io, NULL, NULL);
g_io_channel_set_buffered (pt->in_io, FALSE);
pt->out_watch_id = g_io_add_watch (pt->out_io,
(GIOCondition)(G_IO_IN | G_IO_PRI | G_IO_HUP),
(GIOFunc) read_helper_out,
pt);
// 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);
pt_gen->priv->child_alive = TRUE;
return TRUE;
}
static gboolean
read_helper_out (GIOChannel *source,
GIOCondition condition,
MooTermPtCyg *pt)
{
GError *err = NULL;
gboolean error_occured = FALSE;
g_assert (pt->out_io == source);
if (condition & G_IO_HUP)
{
g_message ("%s: G_IO_HUP", G_STRLOC);
error_occured = TRUE;
}
else if (condition & G_IO_ERR)
{
g_message ("%s: G_IO_ERR", G_STRLOC);
error_occured = TRUE;
}
else if (condition & (G_IO_IN | G_IO_PRI))
{
char buf[READ_CHUNK_SIZE];
int count = 0;
gsize read;
int again = TRY_NUM;
g_io_channel_read_chars (source, buf, 1, &read, &err);
if (read == 1) ++count;
while (again && !err && !error_occured && count < READ_CHUNK_SIZE)
{
if (g_io_channel_get_buffer_condition (source) & G_IO_IN)
{
g_io_channel_read_chars (source, buf + count, 1, &read, &err);
if (read == 1)
{
++count;
}
else
{
if (--again)
g_usleep (SLEEP_TIME);
}
}
else
{
if (--again)
g_usleep (SLEEP_TIME);
}
}
if (count > 0)
moo_term_feed (MOO_TERM_PT(pt)->priv->term, buf, count);
error_occured = (err != NULL);
}
else
{
g_critical ("%s: unknown source condition", G_STRLOC);
}
if (error_occured)
{
if (err)
{
g_message ("%s: %s", G_STRLOC, err->message);
g_error_free (err);
}
g_io_channel_shutdown (pt->in_io, TRUE, NULL);
g_io_channel_unref (pt->in_io);
pt->in_io = NULL;
pt->in = -1;
kill_child (MOO_TERM_PT (pt));
return FALSE;
}
return TRUE;
}
static void
kill_child (MooTermPt *pt_gen)
{
MooTermPtCyg *pt = MOO_TERM_PT_WIN (pt_gen);
if (pt->in_io)
{
char cmd[2] = {HELPER_CMD_CHAR, HELPER_GOODBYE};
pt_write (MOO_TERM_PT (pt), cmd, 2);
g_io_channel_shutdown (pt->in_io, TRUE, NULL);
g_io_channel_unref (pt->in_io);
pt->in_io = NULL;
}
if (pt->out_io)
{
g_io_channel_shutdown (pt->out_io, TRUE, NULL);
g_io_channel_unref (pt->out_io);
pt->out_io = NULL;
}
if (pt->watch_id)
{
g_source_remove (pt->watch_id);
pt->watch_id = 0;
}
if (pt->out_watch_id)
{
g_source_remove (pt->out_watch_id);
pt->out_watch_id = 0;
}
if (pt->pid != (GPid) -1)
{
g_spawn_close_pid (pt->pid);
pt->pid = (GPid) -1;
}
pt->in = -1;
pt->out = -1;
pt->process_id = 0;
if (pt_gen->priv->child_alive)
{
pt_gen->priv->child_alive = FALSE;
g_signal_emit_by_name (pt, "child-died");
}
}
static void
set_size (MooTermPt *pt,
guint width,
guint height)
{
if (pt->priv->child_alive)
pt_write (MOO_TERM_PT (pt), set_size_cmd (width, height), SIZE_CMD_LEN);
}
static void
append (MooTermPt *pt,
const char *data,
guint len)
{
GByteArray *ar = g_byte_array_sized_new (len);
g_byte_array_append (ar, (const guint8*)data, len);
g_queue_push_tail (pt->priv->pending_write, ar);
}
/* writes given data to file, returns TRUE on successful write,
FALSE when could not write al teh data, puts start of leftover
to string, length of it to len, and fills err in case of error */
static gboolean
do_write (MooTermPt *pt_gen,
const char **string,
guint *plen,
GError **err)
{
GIOStatus status;
guint written;
MooTermPtCyg *pt = MOO_TERM_PT_WIN (pt_gen);
g_return_val_if_fail (pt->in_io != NULL, FALSE);
status = g_io_channel_write_chars (pt->in_io, *string,
*plen > WRITE_CHUNK_SIZE ? WRITE_CHUNK_SIZE : *plen,
&written, err);
if (status == G_IO_STATUS_ERROR)
return FALSE;
*string += written;
*plen -= written;
if (!*plen)
*string = NULL;
return TRUE;
}
static gboolean
write_cb (MooTermPt *pt)
{
pt_write (pt, NULL, 0);
return TRUE;
}
static void
start_writer (MooTermPt *pt)
{
if (!pt->priv->pending_write_id)
pt->priv->pending_write_id =
g_idle_add_full (PT_WRITER_PRIORITY,
(GSourceFunc) write_cb,
pt, NULL);
}
static void
stop_writer (MooTermPt *pt)
{
if (pt->priv->pending_write_id)
{
g_source_remove (pt->priv->pending_write_id);
pt->priv->pending_write_id = 0;
}
}
static void
pt_write (MooTermPt *pt,
const char *data,
gssize data_len)
{
g_return_if_fail (data == NULL || data_len != 0);
g_return_if_fail (pt->priv->child_alive);
while (data || !g_queue_is_empty (pt->priv->pending_write))
{
GError *err = NULL;
const char *string;
guint len;
GByteArray *freeme = NULL;
if (!g_queue_is_empty (pt->priv->pending_write))
{
if (data)
{
append (pt, data, data_len > 0 ? (guint)data_len : strlen (data));
data = NULL;
}
freeme = g_queue_peek_head (pt->priv->pending_write);
string = (const char *) freeme->data;
len = freeme->len;
}
else
{
string = data;
len = data_len > 0 ? (guint)data_len : strlen (data);
data = NULL;
}
if (do_write (pt, &string, &len, &err))
{
if (len)
{
if (freeme)
{
memmove (freeme->data, freeme->data + (freeme->len - len), len);
g_byte_array_set_size (freeme, len);
}
else
{
append (pt, string, len);
}
break;
}
else if (freeme)
{
g_byte_array_free (freeme, TRUE);
g_queue_pop_head (pt->priv->pending_write);
}
}
else
{
g_message ("%s: stopping writing to child", G_STRLOC);
kill_child (pt);
}
if (err)
{
g_message ("%s: %s", G_STRLOC, err->message);
g_error_free (err);
}
}
if (!g_queue_is_empty (pt->priv->pending_write))
start_writer (pt);
else
stop_writer (pt);
}
enum {
READ_END = 0,
WRITE_END = 1
};
static gboolean
run_in_helper (const char *cmd,
const char *working_dir,
char **env,
guint width, guint height,
int *hin, int *hout,
GPid *hpid, gulong *hproc_id,
GError **error)
{
/* char *cwidth = NULL, *cheight = NULL; */
int my_stdin = _dup(0);
int my_stdout = _dup(1);
GPid helper = (GPid)INVALID_HANDLE_VALUE;
int helper_in[2] = {-1, -1};
int helper_out[2] = {-1, -1};
char *cmd_line = NULL;
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
GString *helper_binary = NULL;
GPtrArray *saved_env = NULL;
const char **s;
g_return_val_if_fail (cmd != NULL && hin != NULL && hout != NULL &&
hpid != NULL, FALSE);
if(_pipe (helper_in, 512, O_NOINHERIT | O_BINARY) == -1)
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_pipe: %s", g_strerror (errno));
goto error;
}
if(_pipe (helper_out, 512, O_NOINHERIT | O_BINARY) == -1)
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_pipe: %s", g_strerror (errno));
goto error;
}
if (_dup2 (helper_in[READ_END], 0))
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_dup2: %s", g_strerror (errno));
goto error;
}
if (_dup2 (helper_out[WRITE_END], 1))
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_dup2: %s", g_strerror (errno));
goto error;
}
close (helper_in[READ_END]);
close (helper_out[WRITE_END]);
#if 0
// cwidth = g_strdup_printf ("%d", width);
// cheight = g_strdup_printf ("%d", height);
// helper = (GPid) _spawnl(P_NOWAIT,
// HELPER_BINARY,
// HELPER_BINARY,
// cwidth,
// cheight,
// cmd,
// NULL);
#endif
/************************************************************************
* We need to use CreateProcess here in order to be able to create new,
* hidden console
*/
pt = MOO_TERM_PT_CYG (pt_gen);
if (!HELPER_DIR || !HELPER_DIR[0])
{
@ -600,228 +154,81 @@ run_in_helper (const char *cmd,
g_message ("%s: helper '%s'", G_STRLOC, helper_binary->str);
cmd_line = g_strdup_printf ("%s %d %d %s", HELPER_BINARY,
width, height, cmd);
saved_env = g_ptr_array_new ();
if (env)
{
for (s = (const char**)env; *s != NULL; ++s)
{
char **pair = g_strsplit (*s, "=", 2);
if (pair && pair[0])
{
const char *val = g_getenv (pair[0]);
g_ptr_array_add (saved_env, g_strdup (pair[0]));
g_ptr_array_add (saved_env, g_strdup (val));
if (pair[1])
g_setenv (pair[0], pair[1], TRUE);
else
g_unsetenv (pair[0]);
}
g_strfreev (pair);
}
}
TERM_WIDTH (pt_gen),
TERM_HEIGHT (pt_gen),
cmd->cmd_line);
if (HELPER_DIR)
{
const char *var = "PATH";
const char *val = g_getenv (var);
char *newval = 0;
char *new_path;
g_message ("%s: pushing '%s' to %s", G_STRLOC, HELPER_DIR, var);
old_path = g_strdup (g_getenv ("PATH"));
g_message ("%s: pushing '%s' to %s", G_STRLOC, HELPER_DIR, "PATH");
g_ptr_array_add (saved_env, g_strdup (var));
g_ptr_array_add (saved_env, g_strdup (val));
if (val)
newval = g_strdup_printf ("%s;%s", HELPER_DIR, val);
if (old_path)
new_path = g_strdup_printf ("%s;%s", HELPER_DIR, old_path);
else
newval = g_strdup (HELPER_DIR);
new_path = g_strdup (HELPER_DIR);
g_setenv (var, newval, TRUE);
g_free (newval);
g_setenv ("PATH", new_path, TRUE);
g_free (new_path);
}
if (working_dir)
{
const char *val = g_getenv (MOO_TERM_HELPER_ENV);
g_ptr_array_add (saved_env, g_strdup (MOO_TERM_HELPER_ENV));
g_ptr_array_add (saved_env, g_strdup (val));
g_setenv (MOO_TERM_HELPER_ENV, working_dir, TRUE);
}
g_ptr_array_add (saved_env, NULL);
new_cmd = moo_term_command_new (cmd_line, NULL);
g_return_val_if_fail (new_cmd != NULL, FALSE);
g_message ("%s: command line '%s'", G_STRLOC, cmd_line);
memset (&sinfo, 0, sizeof (sinfo));
sinfo.cb = sizeof (STARTUPINFO);
sinfo.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdInput = (HANDLE)_get_osfhandle (0);
sinfo.hStdOutput = (HANDLE)_get_osfhandle (1);
sinfo.hStdError = (HANDLE)_get_osfhandle (2);
result = MOO_TERM_PT_CLASS(moo_term_pt_cyg_parent_class)->
fork_command (pt_gen, new_cmd, HELPER_BINARY, envp, error);
sinfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
sinfo.wShowWindow = SW_HIDE;
if (old_path)
g_setenv ("PATH", old_path, TRUE);
else
g_unsetenv ("PATH");
g_string_free (helper_binary, TRUE);
g_free (old_path);
moo_term_command_free (new_cmd);
if (! CreateProcess (helper_binary->str, cmd_line, NULL, NULL, TRUE,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
NULL,
HELPER_DIR,
&sinfo,
&pinfo))
{
g_set_error (error, MOO_TERM_ERROR, 0,
"CreateProcess: %s",
g_win32_error_message (GetLastError ()));
goto error;
}
g_free (cmd_line);
cmd_line = NULL;
for (s = (const char**)saved_env->pdata; *s != NULL; )
{
const char *var = *s++;
const char *val = *s++;
if (val)
g_setenv (var, val, TRUE);
else
g_unsetenv (var);
}
CloseHandle (pinfo.hThread);
/***********************************************************************/
#if 0
// g_free (cwidth); cwidth = NULL;
// g_free (cheight); cheight = NULL;
// if (helper == (GPid)-1) {
// g_critical ("%s: error in spawn()", G_STRLOC);
// goto error;
// }
#endif
_dup2 (my_stdin, 0);
_dup2 (my_stdout, 1);
close (my_stdin); my_stdin = -1;
close (my_stdout); my_stdout = -1;
/* g_message ("%s: created process pid %d", G_STRLOC, (int)pinfo.dwProcessId); */
*hin = helper_in[WRITE_END];
*hout = helper_out[READ_END];
*hpid = pinfo.hProcess;
*hproc_id = pinfo.dwProcessId;
if (helper_binary)
g_string_free (helper_binary, TRUE);
if (saved_env)
{
g_strfreev ((char**)saved_env->pdata);
g_ptr_array_free (saved_env, FALSE);
}
return TRUE;
/* cleanup on error */
error:
_dup2(my_stdin, 0);
_dup2(my_stdout, 1);
close (helper_in[0]);
close (helper_in[1]);
close (helper_out[0]);
close (helper_out[1]);
#if 0
// if (cwidth) g_free (cwidth);
// if (cheight) g_free (cheight);
#endif
if (cmd_line)
g_free (cmd_line);
CloseHandle ((HANDLE)helper);
if (helper_binary)
g_string_free (helper_binary, TRUE);
if (saved_env)
{
for (s = (const char**)saved_env->pdata; *s != NULL; )
{
const char *var = *s++;
const char *val = *s++;
if (val)
g_setenv (var, val, TRUE);
else
g_unsetenv (var);
}
g_strfreev ((char**)saved_env->pdata);
g_ptr_array_free (saved_env, FALSE);
}
return FALSE;
return result;
}
char
_moo_term_pt_get_erase_char (G_GNUC_UNUSED MooTermPt *pt)
static void
kill_child (MooTermPt *pt)
{
char cmd[2] = {HELPER_CMD_CHAR, HELPER_GOODBYE};
_moo_term_pt_write (pt, cmd, sizeof (cmd));
MOO_TERM_PT_CLASS(moo_term_pt_cyg_parent_class)->kill_child (pt);
}
static void
set_size (MooTermPt *pt,
guint width,
guint height)
{
if (pt->priv->child_alive)
_moo_term_pt_write (MOO_TERM_PT (pt),
set_size_cmd (width, height),
SIZE_CMD_LEN);
}
static char
get_erase_char (G_GNUC_UNUSED MooTermPt *pt)
{
return 127;
}
void
_moo_term_pt_send_intr (MooTermPt *pt)
static void
send_intr (MooTermPt *pt)
{
g_return_if_fail (pt->priv->child_alive);
pt_flush_pending_write (pt);
pt_write (pt, "\3", 1);
}
gboolean
_moo_term_check_cmd (MooTermCommand *cmd,
G_GNUC_UNUSED GError **error)
{
g_return_val_if_fail (cmd != NULL, FALSE);
g_return_val_if_fail (cmd->cmd_line != NULL || cmd->argv != NULL, FALSE);
if (cmd->cmd_line)
{
g_strfreev (cmd->argv);
cmd->argv = NULL;
return TRUE;
}
else
{
GString *cmd_line = NULL;
char **p;
g_return_val_if_fail (cmd->argv[0] != NULL, FALSE);
cmd_line = g_string_new ("");
for (p = cmd->argv; *p != NULL; ++p)
{
if (strchr (*p, ' '))
g_string_append_printf (cmd_line, "\"%s\" ", *p);
else
g_string_append_printf (cmd_line, "%s ", *p);
}
cmd->cmd_line = g_string_free (cmd_line, FALSE);
return TRUE;
}
pt_discard_pending_write (pt);
_moo_term_pt_write (pt, "\3", 1);
}

View File

@ -43,7 +43,7 @@ inline static void pt_discard (GSList **list)
*list = NULL;
}
inline static void pt_flush_pending_write (MooTermPt *pt)
inline static void pt_discard_pending_write (MooTermPt *pt)
{
GList *l;

View File

@ -92,6 +92,8 @@ static void pt_write (MooTermPt *pt,
const char *string,
gssize len);
static void kill_child (MooTermPt *pt);
static void send_intr (MooTermPt *pt);
static char get_erase_char (MooTermPt *pt);
static gboolean read_child_out (GIOChannel *source,
GIOCondition condition,
@ -119,6 +121,8 @@ static void moo_term_pt_unix_class_init (MooTermPtUnixClass *klass)
pt_class->fork_command = fork_command;
pt_class->write = pt_write;
pt_class->kill_child = kill_child;
pt_class->get_erase_char = get_erase_char;
pt_class->send_intr = send_intr;
}
@ -294,7 +298,7 @@ static void kill_child (MooTermPt *pt_gen)
}
stop_writer (pt_gen);
pt_flush_pending_write (pt_gen);
pt_discard_pending_write (pt_gen);
if (pt->master != -1)
{
@ -638,8 +642,8 @@ static void pt_write (MooTermPt *pt,
}
char
_moo_term_pt_get_erase_char (MooTermPt *pt_gen)
static char
get_erase_char (MooTermPt *pt_gen)
{
MooTermPtUnix *pt = MOO_TERM_PT_UNIX (pt_gen);
struct termios tio;
@ -659,11 +663,11 @@ _moo_term_pt_get_erase_char (MooTermPt *pt_gen)
}
void
_moo_term_pt_send_intr (MooTermPt *pt)
static void
send_intr (MooTermPt *pt)
{
g_return_if_fail (pt->priv->child_alive);
pt_flush_pending_write (pt);
pt_discard_pending_write (pt);
pt_write (pt, "\003", 1);
}

View File

@ -0,0 +1,698 @@
/*
* mooterm/mootermpt-win32.c
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*/
#define MOOTERM_COMPILATION
#include "mooterm/mootermpt-private.h"
#include "mooterm/mooterm-private.h"
#include "mooterm/mootermpt-win32.h"
#include "mooutils/moomarshals.h"
#include "mooutils/moocompat.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <errno.h>
#define TRY_NUM 10
#define SLEEP_TIME 10
#define TERM_EMULATION "xterm"
#define READ_CHUNK_SIZE 1024
#define WRITE_CHUNK_SIZE 4096
#define POLL_TIME 5
#define POLL_NUM 1
#define TERM_WIDTH(pt__) (MOO_TERM_PT(pt__)->priv->term->priv->width)
#define TERM_HEIGHT(pt__) (MOO_TERM_PT(pt__)->priv->term->priv->height)
static void moo_term_pt_win_finalize (GObject *object);
static gboolean read_child_out (GIOChannel *source,
GIOCondition condition,
MooTermPtWin *self);
static void set_size (MooTermPt *pt,
guint width,
guint height);
static gboolean fork_command (MooTermPt *pt,
const MooTermCommand *cmd,
const char *working_dir,
char **envp,
GError **error);
static void pt_write (MooTermPt *pt,
const char *string,
gssize len);
static void kill_child (MooTermPt *pt);
static char get_erase_char (MooTermPt *pt);
static void send_intr (MooTermPt *pt);
static gboolean fork_child (const char *cmd_line,
const char *working_dir,
char **env,
guint width,
guint height,
int *in,
int *out,
GPid *pid,
gulong *proc_id,
GError **error);
/* MOO_TYPE_TERM_PT_WIN */
G_DEFINE_TYPE (MooTermPtWin, moo_term_pt_win, MOO_TYPE_TERM_PT)
static void
moo_term_pt_win_class_init (MooTermPtWinClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
MooTermPtClass *pt_class = MOO_TERM_PT_CLASS (klass);
gobject_class->finalize = moo_term_pt_win_finalize;
pt_class->set_size = set_size;
pt_class->fork_command = fork_command;
pt_class->write = pt_write;
pt_class->kill_child = kill_child;
pt_class->send_intr = send_intr;
pt_class->get_erase_char = get_erase_char;
}
static void
moo_term_pt_win_init (MooTermPtWin *pt)
{
MOO_TERM_PT(pt)->priv->child_alive = FALSE;
pt->pid = (GPid) -1;
pt->process_id = 0;
pt->watch_id = 0;
pt->in = -1;
pt->in_io = NULL;
pt->out = -1;
pt->out_io = NULL;
pt->out_watch_id = 0;
}
static void
moo_term_pt_win_finalize (GObject *object)
{
MooTermPtWin *pt = MOO_TERM_PT_WIN (object);
kill_child (MOO_TERM_PT (pt));
G_OBJECT_CLASS (moo_term_pt_win_parent_class)->finalize (object);
}
MooTermCommand *
_moo_term_get_default_shell (void)
{
const char *cmd = NULL;
cmd = g_getenv ("ComSpec");
if (!cmd)
cmd = "cmd.exe";
return moo_term_command_new (cmd, NULL);
}
static gboolean
fork_command (MooTermPt *pt_gen,
const MooTermCommand *cmd,
const char *working_dir,
char **envp,
GError **error)
{
MooTermPtWin *pt;
gboolean result;
g_return_val_if_fail (!pt_gen->priv->child_alive, FALSE);
g_return_val_if_fail (cmd->cmd_line != NULL, FALSE);
pt = MOO_TERM_PT_WIN (pt_gen);
result = fork_child (cmd->cmd_line, working_dir, envp,
TERM_WIDTH (pt), TERM_HEIGHT (pt),
&pt->in, &pt->out, &pt->pid,
&pt->process_id, error);
if (!result)
return FALSE;
else
g_message ("%s: started child pid %d", G_STRLOC,
(int) pt->pid);
pt->in_io = g_io_channel_win32_new_fd (pt->in);
g_io_channel_set_encoding (pt->in_io, NULL, NULL);
pt->out_io = g_io_channel_win32_new_fd (pt->out);
g_io_channel_set_encoding (pt->out_io, NULL, NULL);
g_io_channel_set_buffered (pt->in_io, FALSE);
pt->out_watch_id = g_io_add_watch (pt->out_io,
(GIOCondition)(G_IO_IN | G_IO_PRI | G_IO_HUP),
(GIOFunc) read_child_out,
pt);
pt_gen->priv->child_alive = TRUE;
return TRUE;
}
static gboolean
read_child_out (GIOChannel *source,
GIOCondition condition,
MooTermPtWin *pt)
{
GError *err = NULL;
gboolean error_occured = FALSE;
g_assert (pt->out_io == source);
if (condition & G_IO_HUP)
{
g_message ("%s: G_IO_HUP", G_STRLOC);
error_occured = TRUE;
}
else if (condition & G_IO_ERR)
{
g_message ("%s: G_IO_ERR", G_STRLOC);
error_occured = TRUE;
}
else if (condition & (G_IO_IN | G_IO_PRI))
{
char buf[READ_CHUNK_SIZE];
int count = 0;
gsize read;
int again = TRY_NUM;
g_io_channel_read_chars (source, buf, 1, &read, &err);
if (read == 1) ++count;
while (again && !err && !error_occured && count < READ_CHUNK_SIZE)
{
if (g_io_channel_get_buffer_condition (source) & G_IO_IN)
{
g_io_channel_read_chars (source, buf + count, 1, &read, &err);
if (read == 1)
{
++count;
}
else
{
if (--again)
g_usleep (SLEEP_TIME);
}
}
else
{
if (--again)
g_usleep (SLEEP_TIME);
}
}
if (count > 0)
moo_term_feed (MOO_TERM_PT(pt)->priv->term, buf, count);
error_occured = (err != NULL);
}
else
{
g_critical ("%s: unknown source condition", G_STRLOC);
}
if (error_occured)
{
if (err)
{
g_message ("%s: %s", G_STRLOC, err->message);
g_error_free (err);
}
g_io_channel_shutdown (pt->in_io, TRUE, NULL);
g_io_channel_unref (pt->in_io);
pt->in_io = NULL;
pt->in = -1;
kill_child (MOO_TERM_PT (pt));
return FALSE;
}
return TRUE;
}
static void
kill_child (MooTermPt *pt_gen)
{
MooTermPtWin *pt = MOO_TERM_PT_WIN (pt_gen);
if (pt->in_io)
{
g_io_channel_shutdown (pt->in_io, TRUE, NULL);
g_io_channel_unref (pt->in_io);
pt->in_io = NULL;
}
if (pt->out_io)
{
g_io_channel_shutdown (pt->out_io, TRUE, NULL);
g_io_channel_unref (pt->out_io);
pt->out_io = NULL;
}
if (pt->watch_id)
{
g_source_remove (pt->watch_id);
pt->watch_id = 0;
}
if (pt->out_watch_id)
{
g_source_remove (pt->out_watch_id);
pt->out_watch_id = 0;
}
if (pt->pid != (GPid) -1)
{
g_spawn_close_pid (pt->pid);
pt->pid = (GPid) -1;
}
pt->in = -1;
pt->out = -1;
pt->process_id = 0;
if (pt_gen->priv->child_alive)
{
pt_gen->priv->child_alive = FALSE;
g_signal_emit_by_name (pt, "child-died");
}
}
static void
set_size (MooTermPt *pt,
guint width,
guint height)
{
#warning "Implement me"
}
static void
append (MooTermPt *pt,
const char *data,
guint len)
{
GByteArray *ar = g_byte_array_sized_new (len);
g_byte_array_append (ar, (const guint8*)data, len);
g_queue_push_tail (pt->priv->pending_write, ar);
}
/* writes given data to file, returns TRUE on successful write,
FALSE when could not write al teh data, puts start of leftover
to string, length of it to len, and fills err in case of error */
static gboolean
do_write (MooTermPt *pt_gen,
const char **string,
guint *plen,
GError **err)
{
GIOStatus status;
guint written;
MooTermPtWin *pt = MOO_TERM_PT_WIN (pt_gen);
g_return_val_if_fail (pt->in_io != NULL, FALSE);
status = g_io_channel_write_chars (pt->in_io, *string,
*plen > WRITE_CHUNK_SIZE ? WRITE_CHUNK_SIZE : *plen,
&written, err);
if (status == G_IO_STATUS_ERROR)
return FALSE;
*string += written;
*plen -= written;
if (!*plen)
*string = NULL;
return TRUE;
}
static gboolean
write_cb (MooTermPt *pt)
{
pt_write (pt, NULL, 0);
return TRUE;
}
static void
start_writer (MooTermPt *pt)
{
if (!pt->priv->pending_write_id)
pt->priv->pending_write_id =
g_idle_add_full (PT_WRITER_PRIORITY,
(GSourceFunc) write_cb,
pt, NULL);
}
static void
stop_writer (MooTermPt *pt)
{
if (pt->priv->pending_write_id)
{
g_source_remove (pt->priv->pending_write_id);
pt->priv->pending_write_id = 0;
}
}
static void
pt_write (MooTermPt *pt,
const char *data,
gssize data_len)
{
g_return_if_fail (data == NULL || data_len != 0);
g_return_if_fail (pt->priv->child_alive);
while (data || !g_queue_is_empty (pt->priv->pending_write))
{
GError *err = NULL;
const char *string;
guint len;
GByteArray *freeme = NULL;
if (!g_queue_is_empty (pt->priv->pending_write))
{
if (data)
{
append (pt, data, data_len > 0 ? (guint)data_len : strlen (data));
data = NULL;
}
freeme = g_queue_peek_head (pt->priv->pending_write);
string = (const char *) freeme->data;
len = freeme->len;
}
else
{
string = data;
len = data_len > 0 ? (guint)data_len : strlen (data);
data = NULL;
}
if (do_write (pt, &string, &len, &err))
{
if (len)
{
if (freeme)
{
memmove (freeme->data, freeme->data + (freeme->len - len), len);
g_byte_array_set_size (freeme, len);
}
else
{
append (pt, string, len);
}
break;
}
else if (freeme)
{
g_byte_array_free (freeme, TRUE);
g_queue_pop_head (pt->priv->pending_write);
}
}
else
{
g_message ("%s: stopping writing to child", G_STRLOC);
kill_child (pt);
}
if (err)
{
g_message ("%s: %s", G_STRLOC, err->message);
g_error_free (err);
}
}
if (!g_queue_is_empty (pt->priv->pending_write))
start_writer (pt);
else
stop_writer (pt);
}
enum {
READ_END = 0,
WRITE_END = 1
};
static gboolean
fork_child (const char *cmd_line,
const char *working_dir,
char **env,
guint width, guint height,
int *in, int *out,
GPid *pid, gulong *proc_id,
GError **error)
{
/* char *cwidth = NULL, *cheight = NULL; */
int my_stdin = _dup(0);
int my_stdout = _dup(1);
GPid child = (GPid) INVALID_HANDLE_VALUE;
int child_in[2] = {-1, -1};
int child_out[2] = {-1, -1};
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
GPtrArray *saved_env = NULL;
const char **s;
g_return_val_if_fail (cmd_line != NULL && in != NULL && out != NULL &&
pid != NULL, FALSE);
if(_pipe (child_in, 512, O_NOINHERIT | O_BINARY) == -1)
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_pipe: %s", g_strerror (errno));
goto error;
}
if(_pipe (child_out, 512, O_NOINHERIT | O_BINARY) == -1)
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_pipe: %s", g_strerror (errno));
goto error;
}
if (_dup2 (child_in[READ_END], 0))
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_dup2: %s", g_strerror (errno));
goto error;
}
if (_dup2 (child_out[WRITE_END], 1))
{
g_set_error (error, MOO_TERM_ERROR, errno,
"_dup2: %s", g_strerror (errno));
goto error;
}
close (child_in[READ_END]);
close (child_out[WRITE_END]);
/************************************************************************
* We need to use CreateProcess here in order to be able to create new,
* hidden console
*/
saved_env = g_ptr_array_new ();
if (env)
{
for (s = (const char**) env; *s != NULL; ++s)
{
char **pair = g_strsplit (*s, "=", 2);
if (pair && pair[0])
{
const char *val = g_getenv (pair[0]);
g_ptr_array_add (saved_env, g_strdup (pair[0]));
g_ptr_array_add (saved_env, g_strdup (val));
if (pair[1])
g_setenv (pair[0], pair[1], TRUE);
else
g_unsetenv (pair[0]);
}
g_strfreev (pair);
}
}
g_ptr_array_add (saved_env, NULL);
memset (&sinfo, 0, sizeof (sinfo));
sinfo.cb = sizeof (STARTUPINFO);
sinfo.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdInput = (HANDLE)_get_osfhandle (0);
sinfo.hStdOutput = (HANDLE)_get_osfhandle (1);
sinfo.hStdError = (HANDLE)_get_osfhandle (2);
//sinfo.dwFlags = STARTF_USESTDHANDLES;
sinfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
sinfo.wShowWindow = SW_HIDE;
if (! CreateProcess (NULL, cmd_line, NULL, NULL, TRUE,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
NULL, working_dir, &sinfo, &pinfo))
{
g_set_error (error, MOO_TERM_ERROR, 0,
"CreateProcess: %s",
g_win32_error_message (GetLastError ()));
goto error;
}
for (s = (const char**)saved_env->pdata; *s != NULL; )
{
const char *var = *s++;
const char *val = *s++;
if (val)
g_setenv (var, val, TRUE);
else
g_unsetenv (var);
}
CloseHandle (pinfo.hThread);
/***********************************************************************/
_dup2 (my_stdin, 0);
_dup2 (my_stdout, 1);
close (my_stdin); my_stdin = -1;
close (my_stdout); my_stdout = -1;
g_message ("%s: created process pid %d", G_STRLOC, (int)pinfo.dwProcessId);
*in = child_in[WRITE_END];
*out = child_out[READ_END];
*pid = pinfo.hProcess;
*proc_id = pinfo.dwProcessId;
if (saved_env)
{
g_strfreev ((char**) saved_env->pdata);
g_ptr_array_free (saved_env, FALSE);
}
return TRUE;
/* cleanup on error */
error:
_dup2(my_stdin, 0);
_dup2(my_stdout, 1);
close (child_in[0]);
close (child_in[1]);
close (child_out[0]);
close (child_out[1]);
CloseHandle ((HANDLE) child);
if (saved_env)
{
for (s = (const char**) saved_env->pdata; *s != NULL; )
{
const char *var = *s++;
const char *val = *s++;
if (val)
g_setenv (var, val, TRUE);
else
g_unsetenv (var);
}
g_strfreev ((char**) saved_env->pdata);
g_ptr_array_free (saved_env, FALSE);
}
return FALSE;
}
static char
get_erase_char (G_GNUC_UNUSED MooTermPt *pt)
{
#warning "Implement me"
return 127;
}
static void
send_intr (MooTermPt *pt)
{
#warning "Implement me"
g_return_if_fail (pt->priv->child_alive);
pt_discard_pending_write (pt);
pt_write (pt, "\3", 1);
}
gboolean
_moo_term_check_cmd (MooTermCommand *cmd,
G_GNUC_UNUSED GError **error)
{
g_return_val_if_fail (cmd != NULL, FALSE);
g_return_val_if_fail (cmd->cmd_line != NULL || cmd->argv != NULL, FALSE);
if (cmd->cmd_line)
{
g_strfreev (cmd->argv);
cmd->argv = NULL;
return TRUE;
}
else
{
GString *cmd_line = NULL;
char **p;
g_return_val_if_fail (cmd->argv[0] != NULL, FALSE);
cmd_line = g_string_new ("");
for (p = cmd->argv; *p != NULL; ++p)
{
if (strchr (*p, ' '))
g_string_append_printf (cmd_line, "\"%s\" ", *p);
else
g_string_append_printf (cmd_line, "%s ", *p);
}
cmd->cmd_line = g_string_free (cmd_line, FALSE);
return TRUE;
}
}

View File

@ -0,0 +1,57 @@
/*
* mootermpt-win32.h
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*/
#ifndef MOOTERM_COMPILATION
#error "This file may not be included"
#endif
#ifndef __MOO_TERM_PT_WIN32_H__
#define __MOO_TERM_PT_WIN32_H__
#include <mooterm/mootermpt.h>
G_BEGIN_DECLS
#define MOO_TERM_PT_WIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOO_TYPE_TERM_PT_WIN, MooTermPtWin))
#define MOO_TERM_PT_WIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TERM_PT_WIN, MooTermPtWinClass))
#define MOO_IS_TERM_PT_WIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOO_TYPE_TERM_PT_WIN))
#define MOO_IS_TERM_PT_WIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_TERM_PT_WIN))
#define MOO_TERM_PT_WIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_TERM_PT_WIN, MooTermPtWinClass))
typedef struct _MooTermPtWin MooTermPtWin;
typedef struct _MooTermPtWinClass MooTermPtWinClass;
struct _MooTermPtWin {
MooTermPt parent;
GPid pid;
gulong process_id;
int in;
int out;
GIOChannel *in_io;
GIOChannel *out_io;
guint watch_id;
guint out_watch_id;
};
struct _MooTermPtWinClass {
MooTermPtClass parent_class;
};
G_END_DECLS
#endif /* __MOO_TERM_PT_WIN32_H__ */

View File

@ -64,7 +64,7 @@ static void moo_term_pt_finalize (GObject *object)
{
MooTermPt *pt = MOO_TERM_PT (object);
pt_flush_pending_write (pt);
pt_discard_pending_write (pt);
g_queue_free (pt->priv->pending_write);
g_free (pt->priv);
@ -78,7 +78,7 @@ _moo_term_pt_new (MooTerm *term)
{
MooTermPt *pt;
#ifdef __WIN32__
pt = g_object_new (MOO_TYPE_TERM_PT_CYGWIN, NULL);
pt = g_object_new (MOO_TYPE_TERM_PT_WIN, NULL);
#else /* !__WIN32__ */
pt = g_object_new (MOO_TYPE_TERM_PT_UNIX, NULL);
#endif /* !__WIN32__ */
@ -109,6 +109,22 @@ _moo_term_pt_fork_command (MooTermPt *pt,
}
char
_moo_term_pt_get_erase_char (MooTermPt *pt)
{
g_return_val_if_fail (MOO_IS_TERM_PT (pt), 0);
return MOO_TERM_PT_GET_CLASS(pt)->get_erase_char (pt);
}
void
_moo_term_pt_send_intr (MooTermPt *pt)
{
g_return_if_fail (MOO_IS_TERM_PT (pt));
MOO_TERM_PT_GET_CLASS(pt)->send_intr (pt);
}
void
_moo_term_pt_kill_child (MooTermPt *pt)
{

View File

@ -24,7 +24,8 @@ G_BEGIN_DECLS
#define MOO_TYPE_TERM_PT (moo_term_pt_get_type ())
#define MOO_TYPE_TERM_PT_CYGWIN (moo_term_pt_cyg_get_type ())
#define MOO_TYPE_TERM_PT_CYG (moo_term_pt_cyg_get_type ())
#define MOO_TYPE_TERM_PT_WIN (moo_term_pt_win_get_type ())
#define MOO_TYPE_TERM_PT_UNIX (moo_term_pt_unix_get_type ())
#define MOO_TERM_PT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOO_TYPE_TERM_PT, MooTermPt))
@ -36,6 +37,7 @@ G_BEGIN_DECLS
typedef struct _MooTermPt MooTermPt;
typedef struct _MooTermPtPrivate MooTermPtPrivate;
typedef struct _MooTermPtClass MooTermPtClass;
struct _MooTerm;
struct _MooTermCommand;
@ -60,6 +62,8 @@ struct _MooTermPtClass {
const char *data,
gssize len);
void (*kill_child) (MooTermPt *pt);
char (*get_erase_char) (MooTermPt *pt);
void (*send_intr) (MooTermPt *pt);
/* signals */
void (*child_died) (MooTermPt *pt);
@ -69,6 +73,7 @@ struct _MooTermPtClass {
GType moo_term_pt_get_type (void) G_GNUC_CONST;
GType moo_term_pt_unix_get_type (void) G_GNUC_CONST;
GType moo_term_pt_cyg_get_type (void) G_GNUC_CONST;
GType moo_term_pt_win_get_type (void) G_GNUC_CONST;
/* creates MooTermPtWin or MooTermPtUnix instance, depending on platform */
MooTermPt *_moo_term_pt_new (struct _MooTerm *term);

96
tests/mterm-app.c Normal file
View File

@ -0,0 +1,96 @@
/*
* tests/mterm-app.c
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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 "mterm-ui.h"
#include "mterm-app.h"
#include <mooutils/mooutils-misc.h>
G_DEFINE_TYPE(MooTermApp, moo_term_app, MOO_TYPE_APP)
static gboolean
on_window_close (MooApp *app)
{
return !moo_app_quit (app);
}
static int
moo_term_app_run (MooApp *app)
{
MooTermApp *tapp = MOO_TERM_APP (app);
tapp->window = g_object_new (MOO_TYPE_TERM_WINDOW, NULL);
tapp->term = tapp->window->terminal;
moo_window_set_ui_xml (MOO_WINDOW (tapp->window),
moo_app_get_ui_xml (app));
gtk_widget_show (GTK_WIDGET (tapp->window));
g_signal_connect_swapped (tapp->window, "delete-event",
G_CALLBACK (on_window_close),
tapp);
moo_term_start_default_shell (tapp->term, NULL);
return MOO_APP_CLASS(moo_term_app_parent_class)->run (app);
}
static gboolean
moo_term_app_try_quit (MooApp *app)
{
return MOO_APP_CLASS(moo_term_app_parent_class)->try_quit (app);
}
static void
moo_term_app_class_init (MooTermAppClass *klass)
{
MooAppClass *app_class = MOO_APP_CLASS (klass);
app_class->run = moo_term_app_run;
app_class->try_quit = moo_term_app_try_quit;
}
static void
moo_term_app_init (MooTermApp *app)
{
}
int main (int argc, char *argv[])
{
MooApp *app;
MooUIXML *xml;
gtk_init (&argc, &argv);
// gdk_window_set_debug_updates (TRUE);
moo_set_log_func_window (TRUE);
app = g_object_new (MOO_TYPE_TERM_APP,
"argv", argv,
"short-name", "mterm",
"full-name", "mterm",
"description", "mterm is a terminal emulator app",
NULL);
xml = moo_app_get_ui_xml (app);
moo_ui_xml_add_ui_from_string (xml, MTERM_UI, -1);
if (!moo_app_init (app))
return 0;
return moo_app_run (app);
}

49
tests/mterm-app.h Normal file
View File

@ -0,0 +1,49 @@
/*
* tests/mterm-app.h
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*/
#ifndef __MOO_TERM_APP_H__
#define __MOO_TERM_APP_H__
#include <mooapp/mooapp.h>
#include <mooterm/mootermwindow.h>
#include <gtk/gtk.h>
#define MOO_TYPE_TERM_APP (moo_term_app_get_type ())
#define MOO_TERM_APP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_TERM_APP, MooTermApp))
#define MOO_TERM_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TERM_APP, MooTermAppClass))
#define MOO_IS_TERM_APP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_TERM_APP))
#define MOO_IS_TERM_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_TERM_APP))
#define MOO_TERM_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_TERM_APP, MooTermAppClass))
typedef struct _MooTermApp MooTermApp;
typedef struct _MooTermAppClass MooTermAppClass;
struct _MooTermApp
{
MooApp parent;
MooTermWindow *window;
MooTerm *term;
};
struct _MooTermAppClass
{
MooAppClass parent_class;
};
GType moo_term_app_get_type (void) G_GNUC_CONST;
#endif /* __MOO_TERM_APP_H__ */

88
tests/mterm-ui.xml Normal file
View File

@ -0,0 +1,88 @@
<ui>
<object name="Terminal">
<widget name="Menubar">
<item name="File" label="_File">
<separator/>
<item action="NewEditor"/>
<item action="OpenInEditor"/>
<separator/>
<item action="Restart"/>
<separator/>
<item action="SaveSelection"/>
<separator/>
<item action="Quit"/>
<separator/>
</item>
<item name="Edit" label="E_dit">
<separator/>
<!--
<item name="CopyLastOutput" action="CopyLastOutput"/>
-->
<item action="Copy"/>
<item action="Paste"/>
<separator/>
<item action="SelectAll"/>
<separator/>
</item>
<!--
<item name="GAP" label="_GAP">
<separator/>
<item action="GAPRead"/>
<separator/>
<item action="Restart"/>
<separator/>
</item>
-->
<item name="Tools" label="_Tools"/>
<item name="Settings" label="_Settings">
<separator/>
<item action="ShowToolbar"/>
<item action="ToolbarStyle"/>
<separator/>
<item action="ConfigureShortcuts"/>
<separator/>
<item action="Preferences"/>
<separator/>
</item>
<item name="Help" label="_Help">
<separator/>
<item action="About"/>
<separator/>
</item>
</widget> <!-- Menubar -->
<widget name="Toolbar">
<separator/>
<item action="NewEditor"/>
<item action="OpenInEditor"/>
<separator/>
<item action="Copy"/>
<item action="Paste"/>
<separator/>
<item action="Restart"/>
<separator/>
<item action="Preferences"/>
<separator/>
</widget> <!-- Toolbar -->
<widget name="Popup">
<separator/>
<item action="Copy"/>
<item action="Paste"/>
<separator/>
<item action="SelectAll"/>
<separator/>
</widget>
</object> <!-- Terminal -->
</ui>