From e3be8de51cd988d07cba827ef3fc7bb17f2b2625 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 14 Aug 2004 13:04:18 +0000 Subject: [PATCH] Implement `Restart Session', in both Unix and Windows PuTTY. Largely because Owen questioned whether it was really easy enough to be labelled `fun' in the bug database :-) git-svn-id: svn://svn.tartarus.org/sgt/putty@4453 cda61777-01e9-0310-a592-d414129be87e --- unix/pterm.c | 142 ++++++++++++++++++++---------- window.c | 278 +++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 269 insertions(+), 151 deletions(-) diff --git a/unix/pterm.c b/unix/pterm.c index f23f07b7..04c722c3 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -44,7 +44,8 @@ struct gui_data { GtkWidget *window, *area, *sbar; GtkBox *hbox; GtkAdjustment *sbar_adjust; - GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2; + GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2, + *restartitem; GtkWidget *sessionsmenu; GdkPixmap *pixmap; GdkFont *fonts[4]; /* normal, bold, wide, widebold */ @@ -94,6 +95,8 @@ static int send_raw_mouse; static char *app_name = "pterm"; +static void start_backend(struct gui_data *inst); + char *x_get_default(const char *key) { return XGetDefault(GDK_DISPLAY(), app_name, key); @@ -981,7 +984,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * should never matter. */ output[end] = '\0'; /* NUL-terminate */ - ldisc_send(inst->ldisc, output+start, -2, 1); + if (inst->ldisc) + ldisc_send(inst->ldisc, output+start, -2, 1); } else if (!inst->direct_to_font) { if (!use_ucsoutput) { /* @@ -996,21 +1000,24 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * far as I can tell, and it's poorly documented * even in 2.0, so it'll have to wait. */ - lpage_send(inst->ldisc, CS_ISO8859_1, output+start, - end-start, 1); + if (inst->ldisc) + lpage_send(inst->ldisc, CS_ISO8859_1, output+start, + end-start, 1); } else { /* * We generated our own Unicode key data from the * keysym, so use that instead. */ - luni_send(inst->ldisc, ucsoutput+start, end-start, 1); + if (inst->ldisc) + luni_send(inst->ldisc, ucsoutput+start, end-start, 1); } } else { /* * In direct-to-font mode, we just send the string * exactly as we received it. */ - ldisc_send(inst->ldisc, output+start, end-start, 1); + if (inst->ldisc) + ldisc_send(inst->ldisc, output+start, end-start, 1); } show_mouseptr(inst, 0); @@ -1134,6 +1141,17 @@ gint timer_func(gpointer data) if (inst->cfg.close_on_exit == FORCE_ON || (inst->cfg.close_on_exit == AUTO && exitcode == 0)) exit(0); /* just go. */ + if (inst->ldisc) { + ldisc_free(inst->ldisc); + inst->ldisc = NULL; + } + if (inst->back) { + inst->back->free(inst->backhandle); + inst->backhandle = NULL; + inst->back = NULL; + update_specials_menu(inst); + } + gtk_widget_show(inst->restartitem); } term_update(inst->term); @@ -2732,7 +2750,8 @@ void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; term_pwron(inst->term); - ldisc_send(inst->ldisc, NULL, 0, 0); + if (inst->ldisc) + ldisc_send(inst->ldisc, NULL, 0, 0); } void copy_all_menuitem(GtkMenuItem *item, gpointer data) @@ -2747,7 +2766,8 @@ void special_menuitem(GtkMenuItem *item, gpointer data) int code = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(item), "user-data")); - inst->back->special(inst->backhandle, code); + if (inst->back) + inst->back->special(inst->backhandle, code); } void about_menuitem(GtkMenuItem *item, gpointer data) @@ -2788,11 +2808,13 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) * Flush the line discipline's edit buffer in the case * where local editing has just been disabled. */ - ldisc_send(inst->ldisc, NULL, 0, 0); + if (inst->ldisc) + ldisc_send(inst->ldisc, NULL, 0, 0); /* Pass new config data to the terminal */ term_reconfig(inst->term, &cfg2); /* Pass new config data to the back end */ - inst->back->reconfig(inst->backhandle, &cfg2); + if (inst->back) + inst->back->reconfig(inst->backhandle, &cfg2); /* * Just setting inst->cfg is sufficient to cause colour @@ -3083,6 +3105,17 @@ void new_session_menuitem(GtkMenuItem *item, gpointer data) fork_and_exec_self(inst, -1, NULL); } +void restart_session_menuitem(GtkMenuItem *item, gpointer data) +{ + struct gui_data *inst = (struct gui_data *)data; + + if (!inst->back) { + logevent(inst, "----- Session restarted -----"); + start_backend(inst); + inst->exited = FALSE; + } +} + void saved_session_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; @@ -3104,7 +3137,11 @@ void update_specials_menu(void *frontend) const struct telnet_special *specials; - specials = inst->back->get_specials(inst->backhandle); + if (inst->back) + specials = inst->back->get_specials(inst->backhandle); + else + specials = NULL; + gtk_container_foreach(GTK_CONTAINER(inst->specialsmenu), (GtkCallback)gtk_widget_destroy, NULL); if (specials) { @@ -3130,9 +3167,51 @@ void update_specials_menu(void *frontend) } } -int pt_main(int argc, char **argv) +static void start_backend(struct gui_data *inst) { extern Backend *select_backend(Config *cfg); + char *realhost; + const char *error; + + inst->back = select_backend(&inst->cfg); + + error = inst->back->init((void *)inst, &inst->backhandle, + &inst->cfg, inst->cfg.host, inst->cfg.port, + &realhost, inst->cfg.tcp_nodelay, + inst->cfg.tcp_keepalives); + + if (error) { + char *msg = dupprintf("Unable to open connection to %s:\n%s", + inst->cfg.host, error); + inst->exited = TRUE; + fatal_message_box(inst->window, msg); + sfree(msg); + exit(0); + } + + if (inst->cfg.wintitle[0]) { + set_title(inst, inst->cfg.wintitle); + set_icon(inst, inst->cfg.wintitle); + } else { + char *title = make_default_wintitle(realhost); + set_title(inst, title); + set_icon(inst, title); + sfree(title); + } + inst->back->provide_logctx(inst->backhandle, inst->logctx); + update_specials_menu(inst); + + term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle); + + inst->ldisc = + ldisc_create(&inst->cfg, inst->term, inst->back, inst->backhandle, + inst); + + gtk_widget_hide(inst->restartitem); +} + +int pt_main(int argc, char **argv) +{ extern int cfgbox(Config *cfg); struct gui_data *inst; @@ -3298,6 +3377,9 @@ int pt_main(int argc, char **argv) } while (0) if (new_session) MKMENUITEM("New Session", new_session_menuitem); + MKMENUITEM("Restart Session", restart_session_menuitem); + inst->restartitem = menuitem; + gtk_widget_hide(inst->restartitem); MKMENUITEM("Duplicate Session", dup_session_menuitem); if (saved_sessions) { struct sesslist sesslist; @@ -3363,42 +3445,8 @@ int pt_main(int argc, char **argv) term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines); - inst->back = select_backend(&inst->cfg); - { - char *realhost; - const char *error; - - error = inst->back->init((void *)inst, &inst->backhandle, - &inst->cfg, inst->cfg.host, inst->cfg.port, - &realhost, inst->cfg.tcp_nodelay, - inst->cfg.tcp_keepalives); - - if (error) { - char *msg = dupprintf("Unable to open connection to %s:\n%s", - inst->cfg.host, error); - inst->exited = TRUE; - fatal_message_box(inst->window, msg); - sfree(msg); - return 0; - } - - if (inst->cfg.wintitle[0]) { - set_title(inst, inst->cfg.wintitle); - set_icon(inst, inst->cfg.wintitle); - } else { - char *title = make_default_wintitle(realhost); - set_title(inst, title); - set_icon(inst, title); - sfree(title); - } - } - inst->back->provide_logctx(inst->backhandle, inst->logctx); - update_specials_menu(inst); + start_backend(inst); - term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle); - - inst->ldisc = - ldisc_create(&inst->cfg, inst->term, inst->back, inst->backhandle, inst); ldisc_send(inst->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */ /* now we're reday to deal with the child exit handler being diff --git a/window.c b/window.c index 1c724e2f..4cb60030 100644 --- a/window.c +++ b/window.c @@ -25,9 +25,10 @@ #define IDM_SHOWLOG 0x0010 #define IDM_NEWSESS 0x0020 #define IDM_DUPSESS 0x0030 -#define IDM_RECONF 0x0040 -#define IDM_CLRSB 0x0050 -#define IDM_RESET 0x0060 +#define IDM_RESTART 0x0040 +#define IDM_RECONF 0x0050 +#define IDM_CLRSB 0x0060 +#define IDM_RESET 0x0070 #define IDM_HELP 0x0140 #define IDM_ABOUT 0x0150 #define IDM_SAVEDSESS 0x0160 @@ -182,6 +183,110 @@ void ldisc_update(void *frontend, int echo, int edit) { } +static void start_backend(void) +{ + const char *error; + char msg[1024], *title; + char *realhost; + int i; + + /* + * Select protocol. This is farmed out into a table in a + * separate file to enable an ssh-free variant. + */ + back = NULL; + for (i = 0; backends[i].backend != NULL; i++) + if (backends[i].protocol == cfg.protocol) { + back = backends[i].backend; + break; + } + if (back == NULL) { + char *str = dupprintf("%s Internal Error", appname); + MessageBox(NULL, "Unsupported protocol number found", + str, MB_OK | MB_ICONEXCLAMATION); + sfree(str); + cleanup_exit(1); + } + + error = back->init(NULL, &backhandle, &cfg, + cfg.host, cfg.port, &realhost, cfg.tcp_nodelay, + cfg.tcp_keepalives); + back->provide_logctx(backhandle, logctx); + if (error) { + char *str = dupprintf("%s Error", appname); + sprintf(msg, "Unable to open connection to\n" + "%.800s\n" "%s", cfg.host, error); + MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); + sfree(str); + exit(0); + } + window_name = icon_name = NULL; + if (*cfg.wintitle) { + title = cfg.wintitle; + } else { + sprintf(msg, "%s - %s", realhost, appname); + title = msg; + } + sfree(realhost); + set_title(NULL, title); + set_icon(NULL, title); + + /* + * Connect the terminal to the backend for resize purposes. + */ + term_provide_resize_fn(term, back->size, backhandle); + + /* + * Set up a line discipline. + */ + ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); + + /* + * Destroy the Restart Session menu item. (This will return + * failure if it's already absent, as it will be the very first + * time we call this function. We ignore that, because as long + * as the menu item ends up not being there, we don't care + * whether it was us who removed it or not!) + */ + for (i = 0; i < lenof(popup_menus); i++) { + DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); + } + + session_closed = FALSE; +} + +static void close_session(void) +{ + char morestuff[100]; + int i; + + session_closed = TRUE; + sprintf(morestuff, "%.70s (inactive)", appname); + set_icon(NULL, morestuff); + set_title(NULL, morestuff); + + if (ldisc) { + ldisc_free(ldisc); + ldisc = NULL; + } + if (back) { + back->free(backhandle); + backhandle = NULL; + back = NULL; + update_specials_menu(NULL); + } + + /* + * Show the Restart Session menu item. Do a precautionary + * delete first to ensure we never end up with more than one. + */ + for (i = 0; i < lenof(popup_menus); i++) { + DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); + InsertMenu(popup_menus[i].menu, IDM_DUPSESS, MF_BYCOMMAND | MF_ENABLED, + IDM_RESTART, "&Restart Session"); + } +} + int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; @@ -452,27 +557,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } } - /* - * Select protocol. This is farmed out into a table in a - * separate file to enable an ssh-free variant. - */ - { - int i; - back = NULL; - for (i = 0; backends[i].backend != NULL; i++) - if (backends[i].protocol == cfg.protocol) { - back = backends[i].backend; - break; - } - if (back == NULL) { - char *str = dupprintf("%s Internal Error", appname); - MessageBox(NULL, "Unsupported protocol number found", - str, MB_OK | MB_ICONEXCLAMATION); - sfree(str); - cleanup_exit(1); - } - } - /* Check for invalid Port number (i.e. zero) */ if (cfg.port == 0) { char *str = dupprintf("%s Internal Error", appname); @@ -602,49 +686,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) SetScrollInfo(hwnd, SB_VERT, &si, FALSE); } - /* - * Start up the telnet connection. - */ - { - const char *error; - char msg[1024], *title; - char *realhost; - - error = back->init(NULL, &backhandle, &cfg, - cfg.host, cfg.port, &realhost, cfg.tcp_nodelay, - cfg.tcp_keepalives); - back->provide_logctx(backhandle, logctx); - if (error) { - char *str = dupprintf("%s Error", appname); - sprintf(msg, "Unable to open connection to\n" - "%.800s\n" "%s", cfg.host, error); - MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); - sfree(str); - return 0; - } - window_name = icon_name = NULL; - if (*cfg.wintitle) { - title = cfg.wintitle; - } else { - sprintf(msg, "%s - %s", realhost, appname); - title = msg; - } - sfree(realhost); - set_title(NULL, title); - set_icon(NULL, title); - } - - /* - * Connect the terminal to the backend for resize purposes. - */ - term_provide_resize_fn(term, back->size, backhandle); - - /* - * Set up a line discipline. - */ - ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); - - session_closed = FALSE; + start_backend(); /* * Prepare the mouse handler. @@ -865,13 +907,17 @@ char *do_select(SOCKET skt, int startup) */ void update_specials_menu(void *frontend) { - HMENU m = GetSystemMenu(hwnd, FALSE); + HMENU p; int menu_already_exists = (specials != NULL); int i, j; - specials = back->get_specials(backhandle); + if (back) + specials = back->get_specials(backhandle); + else + specials = NULL; + if (specials) { - HMENU p = CreateMenu(); + p = CreateMenu(); for (i = 0; specials[i].name; i++) { assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX); if (*specials[i].name) @@ -880,15 +926,22 @@ void update_specials_menu(void *frontend) else AppendMenu(p, MF_SEPARATOR, 0, 0); } - for (j = 0; j < lenof(popup_menus); j++) { - if (menu_already_exists) - DeleteMenu(popup_menus[j].menu, - popup_menus[j].specials_submenu_pos, - MF_BYPOSITION); - else - InsertMenu(popup_menus[j].menu, - popup_menus[j].specials_submenu_pos, - MF_BYPOSITION | MF_SEPARATOR, 0, 0); + } else + p = NULL; + + for (j = 0; j < lenof(popup_menus); j++) { + if (menu_already_exists) { + DeleteMenu(popup_menus[j].menu, + popup_menus[j].specials_submenu_pos, + MF_BYPOSITION); + DeleteMenu(popup_menus[j].menu, + popup_menus[j].specials_submenu_pos, + MF_BYPOSITION); + } + if (specials) { + InsertMenu(popup_menus[j].menu, + popup_menus[j].specials_submenu_pos, + MF_BYPOSITION | MF_SEPARATOR, 0, 0); InsertMenu(popup_menus[j].menu, popup_menus[j].specials_submenu_pos, MF_BYPOSITION | MF_POPUP | MF_ENABLED, @@ -925,10 +978,7 @@ void connection_fatal(void *frontend, char *fmt, ...) if (cfg.close_on_exit == FORCE_ON) PostQuitMessage(1); else { - session_closed = TRUE; - sprintf(morestuff, "%.70s (inactive)", appname); - set_icon(NULL, morestuff); - set_title(NULL, morestuff); + close_session(); } } @@ -973,11 +1023,8 @@ static void enact_pending_netevent(void) if (cfg.close_on_exit == FORCE_ON || cfg.close_on_exit == AUTO) PostQuitMessage(0); else { - char morestuff[100]; + close_session(); session_closed = TRUE; - sprintf(morestuff, "%.70s (inactive)", appname); - set_icon(NULL, morestuff); - set_title(NULL, morestuff); MessageBox(hwnd, "Connection closed by remote host", appname, MB_OK | MB_ICONINFORMATION); } @@ -1738,7 +1785,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, time_t now; time(&now); if (now - last_movement > cfg.ping_interval) { - back->special(backhandle, TS_PING); + if (back) + back->special(backhandle, TS_PING); last_movement = now; } } @@ -1841,6 +1889,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, sfree(cl); } break; + case IDM_RESTART: + if (!back) { + logevent(NULL, "----- Session restarted -----"); + start_backend(); + } + + break; case IDM_RECONF: { Config prev_cfg; @@ -1873,7 +1928,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * Flush the line discipline's edit buffer in the * case where local editing has just been disabled. */ - ldisc_send(ldisc, NULL, 0, 0); + if (ldisc) + ldisc_send(ldisc, NULL, 0, 0); if (pal) DeleteObject(pal); logpal = NULL; @@ -1885,7 +1941,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, term_reconfig(term, &cfg); /* Pass new config data to the back end */ - back->reconfig(backhandle, &cfg); + if (back) + back->reconfig(backhandle, &cfg); /* Screen size changed ? */ if (cfg.height != prev_cfg.height || @@ -1993,7 +2050,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case IDM_RESET: term_pwron(term); - ldisc_send(ldisc, NULL, 0, 0); + if (ldisc) + ldisc_send(ldisc, NULL, 0, 0); break; case IDM_ABOUT: showabout(hwnd); @@ -2041,7 +2099,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (!specials || !specials[j].name) break; if (j == i) { - back->special(backhandle, specials[i].code); + if (back) + back->special(backhandle, specials[i].code); net_pending_errors(); } } @@ -2613,7 +2672,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * we're sent. */ term_seen_key_event(term); - ldisc_send(ldisc, buf, len, 1); + if (ldisc) + ldisc_send(ldisc, buf, len, 1); show_mouseptr(0); } } @@ -2661,7 +2721,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, */ term_seen_key_event(term); for (i = 0; i < n; i += 2) { - luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); + if (ldisc) + luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); } free(buff); } @@ -2676,11 +2737,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, buf[1] = wParam; buf[0] = wParam >> 8; term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, buf, 2, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, buf, 2, 1); } else { char c = (unsigned char) wParam; term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, &c, 1, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, &c, 1, 1); } return (0); case WM_CHAR: @@ -2694,7 +2757,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, { char c = (unsigned char)wParam; term_seen_key_event(term); - lpage_send(ldisc, CP_ACP, &c, 1, 1); + if (ldisc) + lpage_send(ldisc, CP_ACP, &c, 1, 1); } return 0; case WM_SETCURSOR: @@ -3990,7 +4054,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } keybuf = nc; term_seen_key_event(term); - luni_send(ldisc, &keybuf, 1, 1); + if (ldisc) + luni_send(ldisc, &keybuf, 1, 1); continue; } @@ -4001,7 +4066,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (in_utf(term) || ucsdata.dbcs_screenfont) { keybuf = alt_sum; term_seen_key_event(term); - luni_send(ldisc, &keybuf, 1, 1); + if (ldisc) + luni_send(ldisc, &keybuf, 1, 1); } else { ch = (char) alt_sum; /* @@ -4014,12 +4080,14 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * everything we're sent. */ term_seen_key_event(term); - ldisc_send(ldisc, &ch, 1, 1); + if (ldisc) + ldisc_send(ldisc, &ch, 1, 1); } alt_sum = 0; } else { term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, &ch, 1, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, &ch, 1, 1); } } else { if(capsOn && ch < 0x80) { @@ -4027,14 +4095,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, cbuf[0] = 27; cbuf[1] = xlat_uskbd2cyrllic(ch); term_seen_key_event(term); - luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); + if (ldisc) + luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } else { char cbuf[2]; cbuf[0] = '\033'; cbuf[1] = ch; term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, - cbuf+!left_alt, 1+!!left_alt, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, + cbuf+!left_alt, 1+!!left_alt, 1); } } show_mouseptr(0); -- 2.11.0