Various error-handling fixes, mostly in Unix PuTTY but one (failure
[u/mdw/putty] / unix / pterm.c
index c207195..00ce217 100644 (file)
@@ -61,12 +61,13 @@ struct gui_data {
     int alt_digits;
     char wintitle[sizeof(((Config *)0)->wintitle)];
     char icontitle[sizeof(((Config *)0)->wintitle)];
-    int master_fd, master_func_id, exited;
+    int master_fd, master_func_id;
     void *ldisc;
     Backend *back;
     void *backhandle;
     Terminal *term;
     void *logctx;
+    int exited;
     struct unicode_data ucsdata;
     Config cfg;
 };
@@ -80,25 +81,60 @@ static int send_raw_mouse;
 
 static char *app_name = "pterm";
 
-char *x_get_default(char *key)
+char *x_get_default(const char *key)
 {
     return XGetDefault(GDK_DISPLAY(), app_name, key);
 }
 
+void connection_fatal(void *frontend, char *p, ...)
+{
+    Terminal *term = (Terminal *)frontend;
+    struct gui_data *inst = (struct gui_data *)term->frontend;
+
+    va_list ap;
+    char *msg;
+    va_start(ap, p);
+    msg = dupvprintf(p, ap);
+    va_end(ap);
+    inst->exited = TRUE;
+    fatal_message_box(inst->window, msg);
+    sfree(msg);
+    if (inst->cfg.close_on_exit == FORCE_ON)
+        cleanup_exit(1);
+}
+
 /*
  * Default settings that are specific to pterm.
  */
-char *platform_default_s(char *name)
+FontSpec platform_default_fontspec(const char *name)
 {
+    FontSpec ret;
     if (!strcmp(name, "Font"))
-       return "fixed";        /* COE_NORMAL works badly in an xterm */
+       strcpy(ret.name, "fixed");
+    else
+       *ret.name = '\0';
+    return ret;
+}
+
+Filename platform_default_filename(const char *name)
+{
+    Filename ret;
+    if (!strcmp(name, "LogFileName"))
+       strcpy(ret.path, "putty.log");
+    else
+       *ret.path = '\0';
+    return ret;
+}
+
+char *platform_default_s(const char *name)
+{
     return NULL;
 }
 
-int platform_default_i(char *name, int def)
+int platform_default_i(const char *name, int def)
 {
     if (!strcmp(name, "CloseOnExit"))
-       return COE_ALWAYS;             /* COE_NORMAL works badly in an xterm */
+       return 2;  /* maps to FORCE_ON after painful rearrangement :-( */
     return def;
 }
 
@@ -112,7 +148,7 @@ void ldisc_update(void *frontend, int echo, int edit)
      */
 }
 
-int askappend(void *frontend, char *filename)
+int askappend(void *frontend, Filename filename)
 {
     /*
      * Logging in an xterm-alike is liable to be something you only
@@ -151,7 +187,7 @@ int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */
  * mouse or a means of faking it, and there is no need to switch
  * buttons around at all.
  */
-Mouse_Button translate_button(void *frontend, Mouse_Button button)
+static Mouse_Button translate_button(Mouse_Button button)
 {
     /* struct gui_data *inst = (struct gui_data *)frontend; */
 
@@ -165,6 +201,17 @@ Mouse_Button translate_button(void *frontend, Mouse_Button button)
 }
 
 /*
+ * Return the top-level GtkWindow associated with a particular
+ * front end instance.
+ */
+void *get_window(void *frontend)
+{
+    Terminal *term = (Terminal *)frontend;
+    struct gui_data *inst = (struct gui_data *)term->frontend;
+    return inst->window;
+}
+
+/*
  * Minimise or restore the window in response to a server-side
  * request.
  */
@@ -937,7 +984,8 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
     x = (event->x - inst->cfg.window_border) / inst->font_width;
     y = (event->y - inst->cfg.window_border) / inst->font_height;
 
-    term_mouse(inst->term, button, act, x, y, shift, ctrl, alt);
+    term_mouse(inst->term, button, translate_button(button), act,
+              x, y, shift, ctrl, alt);
 
     return TRUE;
 }
@@ -964,59 +1012,12 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
     x = (event->x - inst->cfg.window_border) / inst->font_width;
     y = (event->y - inst->cfg.window_border) / inst->font_height;
 
-    term_mouse(inst->term, button, MA_DRAG, x, y, shift, ctrl, alt);
+    term_mouse(inst->term, button, translate_button(button), MA_DRAG,
+              x, y, shift, ctrl, alt);
 
     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 && inst->back->exitcode(inst->backhandle) >= 0) {
-       int exitcode = inst->back->exitcode(inst->backhandle);
-       int clean;
-
-       clean = WIFEXITED(exitcode) && (WEXITSTATUS(exitcode) == 0);
-
-       /*
-        * Terminate now, if the Close On Exit setting is
-        * appropriate.
-        */
-       if (inst->cfg.close_on_exit == COE_ALWAYS ||
-           (inst->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 *)inst->term, 0, message, strlen(message));
-       }
-       inst->exited = 1;
-    }
-}
-
 void frontend_keypress(void *handle)
 {
     struct gui_data *inst = (struct gui_data *)handle;
@@ -1032,18 +1033,14 @@ void frontend_keypress(void *handle)
 gint timer_func(gpointer data)
 {
     struct gui_data *inst = (struct gui_data *)data;
-
-    if (inst->back->exitcode(inst->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
-        * (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.
-        */
-       done_with_pty(inst);
+    int exitcode;
+
+    if (!inst->exited &&
+        (exitcode = inst->back->exitcode(inst->backhandle)) >= 0) {
+       inst->exited = TRUE;
+       if (inst->cfg.close_on_exit == FORCE_ON ||
+           (inst->cfg.close_on_exit == AUTO && exitcode == 0))
+           exit(0);                   /* just go. */
     }
 
     term_update(inst->term);
@@ -1051,28 +1048,19 @@ gint timer_func(gpointer data)
     return TRUE;
 }
 
-void pty_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
+void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
 {
-    struct gui_data *inst = (struct gui_data *)data;
-    char buf[4096];
-    int ret;
-
-    ret = read(sourcefd, buf, sizeof(buf));
-
     /*
-     * Clean termination condition is that either ret == 0, or ret
-     * < 0 and errno == EIO. Not sure why the latter, but it seems
-     * to happen. Boo.
+     * We must process exceptional notifications before ordinary
+     * readability ones, or we may go straight past the urgent
+     * marker.
      */
-    if (ret == 0 || (ret < 0 && errno == EIO)) {
-       done_with_pty(inst);
-    } else if (ret < 0) {
-       perror("read pty master");
-       exit(1);
-    } else if (ret > 0)
-       from_backend(inst->term, 0, buf, ret);
-    term_blink(inst->term, 1);
-    term_out(inst->term);
+    if (condition & GDK_INPUT_EXCEPTION)
+        select_result(sourcefd, 4);
+    if (condition & GDK_INPUT_READ)
+        select_result(sourcefd, 1);
+    if (condition & GDK_INPUT_WRITE)
+        select_result(sourcefd, 2);
 }
 
 void destroy(GtkWidget *widget, gpointer data)
@@ -1263,7 +1251,7 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
        wchar_t *tmp = data;
        int tmplen = len;
 
-       inst->pasteout_data_utf8 = smalloc(len*6);
+       inst->pasteout_data_utf8 = snewn(len*6, char);
        inst->pasteout_data_utf8_len = len*6;
        inst->pasteout_data_utf8_len =
            charset_from_unicode(&tmp, &tmplen, inst->pasteout_data_utf8,
@@ -1274,15 +1262,15 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
            inst->pasteout_data_utf8 = NULL;
        } else {
            inst->pasteout_data_utf8 =
-               srealloc(inst->pasteout_data_utf8,
-                        inst->pasteout_data_utf8_len);
+               sresize(inst->pasteout_data_utf8,
+                       inst->pasteout_data_utf8_len, char);
        }
     } else {
        inst->pasteout_data_utf8 = NULL;
        inst->pasteout_data_utf8_len = 0;
     }
 
-    inst->pasteout_data = smalloc(len*6);
+    inst->pasteout_data = snewn(len*6, char);
     inst->pasteout_data_len = len*6;
     inst->pasteout_data_len = wc_to_mb(inst->ucsdata.line_codepage, 0,
                                       data, len, inst->pasteout_data,
@@ -1293,7 +1281,7 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
        inst->pasteout_data = NULL;
     } else {
        inst->pasteout_data =
-           srealloc(inst->pasteout_data, inst->pasteout_data_len);
+           sresize(inst->pasteout_data, inst->pasteout_data_len, char);
     }
 
     if (gtk_selection_owner_set(inst->area, GDK_SELECTION_PRIMARY,
@@ -1394,7 +1382,7 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
     if (inst->pastein_data)
        sfree(inst->pastein_data);
 
-    inst->pastein_data = smalloc(seldata->length * sizeof(wchar_t));
+    inst->pastein_data = snewn(seldata->length, wchar_t);
     inst->pastein_data_len = seldata->length;
     inst->pastein_data_len =
        mb_to_wc((seldata->type == inst->utf8_string_atom ?
@@ -1510,7 +1498,7 @@ Context get_ctx(void *frontend)
     if (!inst->area->window)
        return NULL;
 
-    dctx = smalloc(sizeof(*dctx));
+    dctx = snew(struct draw_ctx);
     dctx->inst = inst;
     dctx->gc = gdk_gc_new(inst->area->window);
     return dctx;
@@ -1540,17 +1528,19 @@ void do_text_internal(Context ctx, int x, int y, char *text, int len,
 
     int nfg, nbg, t, fontid, shadow, rlen, widefactor;
 
-    nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
-    nbg = 2 * ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
+    nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
+    nfg = 2 * (nfg & 0xF) + (nfg & 0x10 ? 1 : 0);
+    nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
+    nbg = 2 * (nbg & 0xF) + (nbg & 0x10 ? 1 : 0);
     if (attr & ATTR_REVERSE) {
        t = nfg;
        nfg = nbg;
        nbg = t;
     }
     if (inst->cfg.bold_colour && (attr & ATTR_BOLD))
-       nfg++;
+       nfg |= 1;
     if (inst->cfg.bold_colour && (attr & ATTR_BLINK))
-       nbg++;
+       nbg |= 1;
     if (attr & TATTR_ACTCURS) {
        nfg = NCOLOURS-2;
        nbg = NCOLOURS-1;
@@ -1605,7 +1595,7 @@ void do_text_internal(Context ctx, int x, int y, char *text, int len,
        wchar_t *wcs;
        int i;
 
-       wcs = smalloc(sizeof(wchar_t) * (len+1));
+       wcs = snewn(len+1, wchar_t);
        for (i = 0; i < len; i++) {
            wcs[i] = (wchar_t) ((attr & CSET_MASK) + (text[i] & CHAR_MASK));
        }
@@ -1632,7 +1622,7 @@ void do_text_internal(Context ctx, int x, int y, char *text, int len,
             * and (c) the clip rectangle should prevent it causing
             * trouble anyway.
             */
-           gwcs = smalloc(sizeof(GdkWChar) * (len*2+1));
+           gwcs = snewn(len*2+1, GdkWChar);
            memset(gwcs, 0, sizeof(GdkWChar) * (len*2+1));
            /*
             * FIXME: when we have a wide-char equivalent of
@@ -1646,7 +1636,7 @@ void do_text_internal(Context ctx, int x, int y, char *text, int len,
                             gwcs, len*2);
            sfree(gwcs);
        } else {
-           gcs = smalloc(sizeof(GdkWChar) * (len+1));
+           gcs = snewn(len+1, gchar);
            wc_to_mb(inst->fontinfo[fontid].charset, 0,
                     wcs, len, gcs, len, ".", NULL, NULL);
            gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc,
@@ -1951,11 +1941,29 @@ void modalfatalbox(char *p, ...)
     exit(1);
 }
 
+void cmdline_error(char *p, ...)
+{
+    va_list ap;
+    fprintf(stderr, "plink: ");
+    va_start(ap, p);
+    vfprintf(stderr, p, ap);
+    va_end(ap);
+    fputc('\n', stderr);
+    exit(1);
+}
+
 char *get_x_display(void *frontend)
 {
     return gdk_get_display();
 }
 
+long get_windowid(void *frontend)
+{
+    Terminal *term = (Terminal *)frontend;
+    struct gui_data *inst = (struct gui_data *)(term->frontend);
+    return (long)GDK_WINDOW_XWINDOW(inst->area->window);
+}
+
 static void help(FILE *fp) {
     if(fprintf(fp,
 "pterm option summary:\n"
@@ -1987,6 +1995,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
 {
     int err = 0;
     extern char **pty_argv;           /* declared in pty.c */
+    extern int use_pty_argv;
 
     /*
      * Macros to make argument handling easier. Note that because
@@ -2015,29 +2024,43 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
     char *val;
     while (--argc > 0) {
        char *p = *++argv;
+        int ret;
+
+        ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
+                                    do_everything ? 1 : -1, cfg);
+
+       if (ret == -2) {
+           cmdline_error("option \"%s\" requires an argument", p);
+       } else if (ret == 2) {
+           --argc, ++argv;            /* skip next argument */
+            continue;
+       } else if (ret == 1) {
+            continue;
+        }
+
        if (!strcmp(p, "-fn") || !strcmp(p, "-font")) {
            EXPECTS_ARG;
            SECOND_PASS_ONLY;
-           strncpy(cfg->font, val, sizeof(cfg->font));
-           cfg->font[sizeof(cfg->font)-1] = '\0';
+           strncpy(cfg->font.name, val, sizeof(cfg->font.name));
+           cfg->font.name[sizeof(cfg->font.name)-1] = '\0';
 
        } else if (!strcmp(p, "-fb")) {
            EXPECTS_ARG;
            SECOND_PASS_ONLY;
-           strncpy(cfg->boldfont, val, sizeof(cfg->boldfont));
-           cfg->boldfont[sizeof(cfg->boldfont)-1] = '\0';
+           strncpy(cfg->boldfont.name, val, sizeof(cfg->boldfont.name));
+           cfg->boldfont.name[sizeof(cfg->boldfont.name)-1] = '\0';
 
        } else if (!strcmp(p, "-fw")) {
            EXPECTS_ARG;
            SECOND_PASS_ONLY;
-           strncpy(cfg->widefont, val, sizeof(cfg->widefont));
-           cfg->widefont[sizeof(cfg->widefont)-1] = '\0';
+           strncpy(cfg->widefont.name, val, sizeof(cfg->widefont.name));
+           cfg->widefont.name[sizeof(cfg->widefont.name)-1] = '\0';
 
        } else if (!strcmp(p, "-fwb")) {
            EXPECTS_ARG;
            SECOND_PASS_ONLY;
-           strncpy(cfg->wideboldfont, val, sizeof(cfg->wideboldfont));
-           cfg->wideboldfont[sizeof(cfg->wideboldfont)-1] = '\0';
+           strncpy(cfg->wideboldfont.name, val, sizeof(cfg->wideboldfont.name));
+           cfg->wideboldfont.name[sizeof(cfg->wideboldfont.name)-1] = '\0';
 
        } else if (!strcmp(p, "-cs")) {
            EXPECTS_ARG;
@@ -2093,14 +2116,14 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
                cfg->colours[index][2] = col.blue / 256;
            }
 
-       } else if (!strcmp(p, "-e")) {
+       } else if (use_pty_argv && !strcmp(p, "-e")) {
            /* This option swallows all further arguments. */
            if (!do_everything)
                break;
 
            if (--argc > 0) {
                int i;
-               pty_argv = smalloc((argc+1) * sizeof(char *));
+               pty_argv = snewn(argc+1, char *);
                ++argv;
                for (i = 0; i < argc; i++)
                    pty_argv[i] = argv[i];
@@ -2118,8 +2141,8 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
        } else if (!strcmp(p, "-log")) {
            EXPECTS_ARG;
            SECOND_PASS_ONLY;
-           strncpy(cfg->logfilename, val, sizeof(cfg->logfilename));
-           cfg->logfilename[sizeof(cfg->logfilename)-1] = '\0';
+           strncpy(cfg->logfilename.path, val, sizeof(cfg->logfilename.path));
+           cfg->logfilename.path[sizeof(cfg->logfilename.path)-1] = '\0';
            cfg->logtype = LGTYP_DEBUG;
 
        } else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) {
@@ -2162,6 +2185,10 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
            help(stdout);
            exit(0);
            
+       } else if(p[0] != '-' && (!do_everything ||
+                                  process_nonoption_arg(p, cfg))) {
+            /* do nothing */
+
        } else {
            err = 1;
            fprintf(stderr, "pterm: unrecognized option '%s'\n", p);
@@ -2246,10 +2273,22 @@ static int set_font_info(struct gui_data *inst, int fontid)
     return retval;
 }
 
-int main(int argc, char **argv)
+int uxsel_input_add(int fd, int rwx) {
+    int flags = 0;
+    if (rwx & 1) flags |= GDK_INPUT_READ;
+    if (rwx & 2) flags |= GDK_INPUT_WRITE;
+    if (rwx & 4) flags |= GDK_INPUT_EXCEPTION;
+    return gdk_input_add(fd, flags, fd_input_func, NULL);
+}
+
+void uxsel_input_remove(int id) {
+    gdk_input_remove(id);
+}
+
+int pt_main(int argc, char **argv)
 {
-    extern int pty_master_fd;         /* declared in pty.c */
-    extern void pty_pre_init(void);    /* declared in pty.c */
+    extern Backend *select_backend(Config *cfg);
+    extern int cfgbox(Config *cfg);
     struct gui_data *inst;
     int font_charset;
 
@@ -2257,14 +2296,12 @@ int main(int argc, char **argv)
      * it */
     block_signal(SIGCHLD, 1);
 
-    pty_pre_init();
-
     gtk_init(&argc, &argv);
 
     /*
      * Create an instance structure and initialise to zeroes
      */
-    inst = smalloc(sizeof(*inst));
+    inst = snew(struct gui_data);
     memset(inst, 0, sizeof(*inst));
     inst->alt_keycode = -1;            /* this one needs _not_ to be zero */
 
@@ -2274,37 +2311,43 @@ int main(int argc, char **argv)
     if (do_cmdline(argc, argv, 1, &inst->cfg))
        exit(1);                       /* post-defaults, do everything */
 
-    inst->fonts[0] = gdk_font_load(inst->cfg.font);
+    cmdline_run_saved(&inst->cfg);
+
+    if (!*inst->cfg.host && !cfgbox(&inst->cfg))
+       exit(0);                       /* config box hit Cancel */
+
+    inst->fonts[0] = gdk_font_load(inst->cfg.font.name);
     if (!inst->fonts[0]) {
-       fprintf(stderr, "pterm: unable to load font \"%s\"\n", inst->cfg.font);
+       fprintf(stderr, "pterm: unable to load font \"%s\"\n",
+               inst->cfg.font.name);
        exit(1);
     }
     font_charset = set_font_info(inst, 0);
-    if (inst->cfg.boldfont[0]) {
-       inst->fonts[1] = gdk_font_load(inst->cfg.boldfont);
+    if (inst->cfg.boldfont.name[0]) {
+       inst->fonts[1] = gdk_font_load(inst->cfg.boldfont.name);
        if (!inst->fonts[1]) {
            fprintf(stderr, "pterm: unable to load bold font \"%s\"\n",
-                   inst->cfg.boldfont);
+                   inst->cfg.boldfont.name);
            exit(1);
        }
        set_font_info(inst, 1);
     } else
        inst->fonts[1] = NULL;
-    if (inst->cfg.widefont[0]) {
-       inst->fonts[2] = gdk_font_load(inst->cfg.widefont);
+    if (inst->cfg.widefont.name[0]) {
+       inst->fonts[2] = gdk_font_load(inst->cfg.widefont.name);
        if (!inst->fonts[2]) {
            fprintf(stderr, "pterm: unable to load wide font \"%s\"\n",
-                   inst->cfg.boldfont);
+                   inst->cfg.widefont.name);
            exit(1);
        }
        set_font_info(inst, 2);
     } else
        inst->fonts[2] = NULL;
-    if (inst->cfg.wideboldfont[0]) {
-       inst->fonts[3] = gdk_font_load(inst->cfg.wideboldfont);
+    if (inst->cfg.wideboldfont.name[0]) {
+       inst->fonts[3] = gdk_font_load(inst->cfg.wideboldfont.name);
        if (!inst->fonts[3]) {
            fprintf(stderr, "pterm: unable to load wide/bold font \"%s\"\n",
-                   inst->cfg.boldfont);
+                   inst->cfg.wideboldfont.name);
            exit(1);
        }
        set_font_info(inst, 3);
@@ -2322,11 +2365,6 @@ int main(int argc, char **argv)
 
     inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
-    if (inst->cfg.wintitle[0])
-       set_title(inst, inst->cfg.wintitle);
-    else
-       set_title(inst, "pterm");
-
     /*
      * Set up the colour map.
      */
@@ -2422,28 +2460,49 @@ int main(int argc, char **argv)
     inst->logctx = log_init(inst, &inst->cfg);
     term_provide_logctx(inst->term, inst->logctx);
 
-    inst->back = &pty_backend;
-    inst->back->init((void *)inst->term, &inst->backhandle, &inst->cfg,
-                    NULL, 0, NULL, 0);
+    uxsel_init();
+
+    term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines);
+
+    inst->back = select_backend(&inst->cfg);
+    {
+       char *realhost, *error;
+
+       error = inst->back->init((void *)inst->term, &inst->backhandle,
+                                 &inst->cfg, inst->cfg.host, inst->cfg.port,
+                                 &realhost, inst->cfg.tcp_nodelay);
+
+       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);
+        else {
+            char *title = make_default_wintitle(realhost);
+            set_title(inst, title);
+            sfree(title);
+        }
+    }
     inst->back->provide_logctx(inst->backhandle, inst->logctx);
 
     term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle);
 
-    term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines);
-
     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 */
 
-    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);
-
     /* now we're reday to deal with the child exit handler being
      * called */
     block_signal(SIGCHLD, 0);
-    
+
+    inst->exited = FALSE;
+
     gtk_main();
 
     return 0;