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 :-)

[originally from svn r4453]
This commit is contained in:
Simon Tatham 2004-08-14 13:04:18 +00:00
Родитель f16d8aff82
Коммит 0047bbe70f
2 изменённых файлов: 269 добавлений и 151 удалений

Просмотреть файл

@ -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;
start_backend(inst);
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);
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

278
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;
}
}
@ -1840,6 +1888,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (freecl)
sfree(cl);
}
break;
case IDM_RESTART:
if (!back) {
logevent(NULL, "----- Session restarted -----");
start_backend();
}
break;
case IDM_RECONF:
{
@ -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);