X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/887035a593c8c0a1af853657c80046e17dc5581a..b9d7bcadee831e9b59fb785f2464a5fc1897bd1a:/unix/pterm.c diff --git a/unix/pterm.c b/unix/pterm.c index c072e7a9..2791693a 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -3,14 +3,19 @@ * back end, all running as a GTK application. Wish me luck. */ +#define _GNU_SOURCE + #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -47,13 +52,15 @@ struct gui_data { int alt_keycode; char wintitle[sizeof(((Config *)0)->wintitle)]; char icontitle[sizeof(((Config *)0)->wintitle)]; + int master_fd, master_func_id, exited; + void *ldisc; }; static struct gui_data the_inst; static struct gui_data *inst = &the_inst; /* so we always write `inst->' */ static int send_raw_mouse; -void ldisc_update(int echo, int edit) +void ldisc_update(void *frontend, int echo, int edit) { /* * This is a stub in pterm. If I ever produce a Unix @@ -786,7 +793,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) printf("\n"); #endif - ldisc_send(output+start, end-start, 1); + ldisc_send(inst->ldisc, output+start, end-start, 1); show_mouseptr(0); term_seen_key_event(term); term_out(term); @@ -870,21 +877,81 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) return TRUE; } +void done_with_pty(struct gui_data *inst) +{ + extern void pty_close(void); + + if (inst->master_fd >= 0) { + pty_close(); + inst->master_fd = -1; + gtk_input_remove(inst->master_func_id); + } + + if (!inst->exited && back->exitcode(backhandle) >= 0) { + int exitcode = back->exitcode(backhandle); + int clean; + + clean = WIFEXITED(exitcode) && (WEXITSTATUS(exitcode) == 0); + + /* + * Terminate now, if the Close On Exit setting is + * appropriate. + */ + if (cfg.close_on_exit == COE_ALWAYS || + (cfg.close_on_exit == COE_NORMAL && clean)) + exit(0); + + /* + * Otherwise, output an indication that the session has + * closed. + */ + { + char message[512]; + if (WIFEXITED(exitcode)) + sprintf(message, "\r\n[pterm: process terminated with exit" + " code %d]\r\n", WEXITSTATUS(exitcode)); + else if (WIFSIGNALED(exitcode)) +#ifdef HAVE_NO_STRSIGNAL + sprintf(message, "\r\n[pterm: process terminated on signal" + " %d]\r\n", WTERMSIG(exitcode)); +#else + sprintf(message, "\r\n[pterm: process terminated on signal" + " %d (%.400s)]\r\n", WTERMSIG(exitcode), + strsignal(WTERMSIG(exitcode))); +#endif + from_backend((void *)term, 0, message, strlen(message)); + } + inst->exited = 1; + } +} + +void frontend_keypress(void *handle) +{ + struct gui_data *inst = (struct gui_data *)handle; + + /* + * If our child process has exited but not closed, terminate on + * any keypress. + */ + if (inst->exited) + exit(0); +} + gint timer_func(gpointer data) { - /* struct gui_data *inst = (struct gui_data *)data; */ - extern int pty_child_is_dead(); /* declared in pty.c */ + struct gui_data *inst = (struct gui_data *)data; - if (pty_child_is_dead()) { + if (back->exitcode(backhandle) >= 0) { /* * The primary child process died. We could keep the * terminal open for remaining subprocesses to output to, * but conventional wisdom seems to feel that that's the - * Wrong Thing for an xterm-alike, so we bail out now. This - * would be easy enough to change or make configurable if - * necessary. + * Wrong Thing for an xterm-alike, so we bail out now + * (though we don't necessarily _close_ the window, + * depending on the state of Close On Exit). This would be + * easy enough to change or make configurable if necessary. */ - exit(0); + done_with_pty(inst); } term_update(term); @@ -894,7 +961,7 @@ gint timer_func(gpointer data) void pty_input_func(gpointer data, gint sourcefd, GdkInputCondition condition) { - /* struct gui_data *inst = (struct gui_data *)data; */ + struct gui_data *inst = (struct gui_data *)data; char buf[4096]; int ret; @@ -906,14 +973,11 @@ void pty_input_func(gpointer data, gint sourcefd, GdkInputCondition condition) * to happen. Boo. */ if (ret == 0 || (ret < 0 && errno == EIO)) { - exit(0); - } - - if (ret < 0) { + done_with_pty(inst); + } else if (ret < 0) { perror("read pty master"); exit(1); - } - if (ret > 0) + } else if (ret > 0) from_backend(term, 0, buf, ret); term_blink(term, 1); term_out(term); @@ -1028,6 +1092,14 @@ void real_palette_set(int n, int r, int g, int b) n, r, g, b); } +void set_window_background(void) +{ + if (inst->area && inst->area->window) + gdk_window_set_background(inst->area->window, &inst->cols[18]); + if (inst->window && inst->window->window) + gdk_window_set_background(inst->window->window, &inst->cols[18]); +} + void palette_set(int n, int r, int g, int b) { static const int first[21] = { @@ -1038,6 +1110,8 @@ void palette_set(int n, int r, int g, int b) real_palette_set(first[n], r, g, b); if (first[n] >= 18) real_palette_set(first[n] + 1, r, g, b); + if (first[n] == 18) + set_window_background(); } void palette_reset(void) @@ -1072,6 +1146,8 @@ void palette_reset(void) g_error("pterm: couldn't allocate colour %d (#%02x%02x%02x)\n", i, cfg.colours[i][0], cfg.colours[i][1], cfg.colours[i][2]); } + + set_window_background(); } void write_clip(wchar_t * data, int len, int must_deselect) @@ -1759,6 +1835,11 @@ int main(int argc, char **argv) if (do_cmdline(argc, argv, 1)) /* post-defaults, do everything */ exit(1); + /* + * Initialise the whole instance structure to zeroes + */ + memset(inst, 0, sizeof(*inst)); + inst->fonts[0] = gdk_font_load(cfg.font); if (!inst->fonts[0]) { fprintf(stderr, "pterm: unable to load font \"%s\"\n", cfg.font); @@ -1870,6 +1951,8 @@ int main(int argc, char **argv) gtk_widget_show(GTK_WIDGET(inst->hbox)); gtk_widget_show(inst->window); + set_window_background(); + inst->textcursor = make_mouse_ptr(GDK_XTERM); inst->rawcursor = make_mouse_ptr(GDK_LEFT_PTR); inst->blankcursor = make_mouse_ptr(-1); @@ -1880,12 +1963,19 @@ int main(int argc, char **argv) term = term_init(); back = &pty_backend; - back->init((void *)term, NULL, 0, NULL, 0); + back->init((void *)term, &backhandle, NULL, 0, NULL, 0); + + term_provide_resize_fn(term, back->size, backhandle); term_size(term, cfg.height, cfg.width, cfg.savelines); - ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */ - gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst); + inst->ldisc = ldisc_create(term, back, backhandle, inst); + ldisc_send(inst->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */ + + inst->master_fd = pty_master_fd; + inst->exited = FALSE; + inst->master_func_id = gdk_input_add(pty_master_fd, GDK_INPUT_READ, + pty_input_func, inst); gtk_main();