Implement `Restart Session', in both Unix and Windows PuTTY. Largely
[u/mdw/putty] / unix / pterm.c
index f23f07b..04c722c 100644 (file)
@@ -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