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
parent
d1f8889eaf
commit
84e7bd1fe8
10
.hgignore
10
.hgignore
|
@ -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
|
||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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>
|
Loading…
Reference in New Issue