]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/gtkwin.c
Giant const-correctness patch of doom!
[PuTTY.git] / unix / gtkwin.c
index 03f2855159ff7c19afd05fff01b292ebd05d967b..e8345881cd803d391da8aa1ccf6fdca7433bd99f 100644 (file)
@@ -31,6 +31,8 @@
 
 #define PUTTY_DO_GLOBALS              /* actually _define_ globals */
 
+#define MAY_REFER_TO_GTK_IN_HEADERS
+
 #include "putty.h"
 #include "terminal.h"
 #include "gtkfont.h"
@@ -91,8 +93,8 @@ struct gui_data {
     int ignore_sbar;
     int mouseptr_visible;
     int busy_status;
-    guint term_paste_idle_id;
-    guint term_exit_idle_id;
+    guint toplevel_callback_idle_id;
+    int idle_fn_scheduled, quit_fn_scheduled;
     int alt_keycode;
     int alt_digits;
     char *wintitle;
@@ -131,16 +133,17 @@ struct draw_ctx {
 
 static int send_raw_mouse;
 
-static char *app_name = "pterm";
+static const char *app_name = "pterm";
 
 static void start_backend(struct gui_data *inst);
+static void exit_callback(void *vinst);
 
 char *x_get_default(const char *key)
 {
     return XGetDefault(GDK_DISPLAY(), app_name, key);
 }
 
-void connection_fatal(void *frontend, char *p, ...)
+void connection_fatal(void *frontend, const char *p, ...)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
 
@@ -149,11 +152,10 @@ void connection_fatal(void *frontend, char *p, ...)
     va_start(ap, p);
     msg = dupvprintf(p, ap);
     va_end(ap);
-    inst->exited = TRUE;
     fatal_message_box(inst->window, msg);
     sfree(msg);
-    if (conf_get_int(inst->conf, CONF_close_on_exit) == FORCE_ON)
-        cleanup_exit(1);
+
+    queue_toplevel_callback(exit_callback, inst);
 }
 
 /*
@@ -192,7 +194,7 @@ int platform_default_i(const char *name, int def)
 }
 
 /* Dummy routine, only required in plink. */
-void ldisc_update(void *frontend, int echo, int edit)
+void frontend_echoedit_update(void *frontend, int echo, int edit)
 {
 }
 
@@ -219,7 +221,7 @@ int from_backend_eof(void *frontend)
     return TRUE;   /* do respond to incoming EOF with outgoing */
 }
 
-int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
+int get_userpass_input(prompts_t *p, const unsigned char *in, int inlen)
 {
     struct gui_data *inst = (struct gui_data *)p->frontend;
     int ret;
@@ -883,7 +885,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
         * NetHack keypad mode.
         */
        if (nethack_mode) {
-           char *keys = NULL;
+           const char *keys = NULL;
            switch (event->keyval) {
              case GDK_KP_1: case GDK_KP_End: keys = "bB\002"; break;
              case GDK_KP_2: case GDK_KP_Down: keys = "jJ\012"; break;
@@ -1221,7 +1223,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
 void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data)
 {
     struct gui_data *inst = (struct gui_data *)data;
-    lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), 1);
+    if (inst->ldisc)
+        lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), 1);
     show_mouseptr(inst, 0);
     term_seen_key_event(inst->term);
 }
@@ -1231,26 +1234,32 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
                         GdkEventType type, guint ebutton, guint state,
                         gdouble ex, gdouble ey)
 {
-    int shift, ctrl, alt, x, y, button, act;
+    int shift, ctrl, alt, x, y, button, act, raw_mouse_mode;
 
     /* Remember the timestamp. */
     inst->input_event_time = timestamp;
 
     show_mouseptr(inst, 1);
 
-    if (ebutton == 4 && type == GDK_BUTTON_PRESS) {
-       term_scroll(inst->term, 0, -5);
-       return TRUE;
-    }
-    if (ebutton == 5 && type == GDK_BUTTON_PRESS) {
-       term_scroll(inst->term, 0, +5);
-       return TRUE;
-    }
-
     shift = state & GDK_SHIFT_MASK;
     ctrl = state & GDK_CONTROL_MASK;
     alt = state & GDK_MOD1_MASK;
 
+    raw_mouse_mode =
+        send_raw_mouse && !(shift && conf_get_int(inst->conf,
+                                                  CONF_mouse_override));
+
+    if (!raw_mouse_mode) {
+        if (ebutton == 4 && type == GDK_BUTTON_PRESS) {
+            term_scroll(inst->term, 0, -5);
+            return TRUE;
+        }
+        if (ebutton == 5 && type == GDK_BUTTON_PRESS) {
+            term_scroll(inst->term, 0, +5);
+            return TRUE;
+        }
+    }
+
     if (ebutton == 3 && ctrl) {
        gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL,
                       ebutton, timestamp);
@@ -1263,6 +1272,10 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
        button = MBT_MIDDLE;
     else if (ebutton == 3)
        button = MBT_RIGHT;
+    else if (ebutton == 4)
+       button = MBT_WHEEL_UP;
+    else if (ebutton == 5)
+       button = MBT_WHEEL_DOWN;
     else
        return FALSE;                  /* don't even know what button! */
 
@@ -1274,9 +1287,7 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
       default: return FALSE;          /* don't know this event type */
     }
 
-    if (send_raw_mouse && !(shift && conf_get_int(inst->conf,
-                                                 CONF_mouse_override)) &&
-       act != MA_CLICK && act != MA_RELEASE)
+    if (raw_mouse_mode && act != MA_CLICK && act != MA_RELEASE)
        return TRUE;                   /* we ignore these in raw mouse mode */
 
     x = (ex - inst->window_border) / inst->font_width;
@@ -1358,12 +1369,12 @@ void frontend_keypress(void *handle)
      * any keypress.
      */
     if (inst->exited)
-       exit(0);
+       cleanup_exit(0);
 }
 
-static gint idle_exit_func(gpointer data)
+static void exit_callback(void *vinst)
 {
-    struct gui_data *inst = (struct gui_data *)data;
+    struct gui_data *inst = (struct gui_data *)vinst;
     int exitcode, close_on_exit;
 
     if (!inst->exited &&
@@ -1377,47 +1388,128 @@ static gint idle_exit_func(gpointer data)
            ldisc_free(inst->ldisc);
            inst->ldisc = NULL;
        }
-       if (inst->back) {
-           inst->back->free(inst->backhandle);
-           inst->backhandle = NULL;
-           inst->back = NULL;
-            term_provide_resize_fn(inst->term, NULL, NULL);
-           update_specials_menu(inst);
-       }
+        inst->back->free(inst->backhandle);
+        inst->backhandle = NULL;
+        inst->back = NULL;
+        term_provide_resize_fn(inst->term, NULL, NULL);
+        update_specials_menu(inst);
        gtk_widget_set_sensitive(inst->restartitem, TRUE);
     }
+}
+
+void notify_remote_exit(void *frontend)
+{
+    struct gui_data *inst = (struct gui_data *)frontend;
+
+    queue_toplevel_callback(exit_callback, inst);
+}
+
+static void notify_toplevel_callback(void *frontend);
+
+static gint quit_toplevel_callback_func(gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+
+    notify_toplevel_callback(inst);
+
+    inst->quit_fn_scheduled = FALSE;
+
+    return 0;
+}
+
+static gint idle_toplevel_callback_func(gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+
+    if (gtk_main_level() > 1) {
+        /*
+         * We don't run the callbacks if we're in the middle of a
+         * subsidiary gtk_main. Instead, ask for a callback when we
+         * get back out of the subsidiary main loop (if we haven't
+         * already arranged one), so we can reschedule ourself then.
+         */
+        if (!inst->quit_fn_scheduled) {
+            gtk_quit_add(2, quit_toplevel_callback_func, inst);
+            inst->quit_fn_scheduled = TRUE;
+        }
+        /*
+         * And unschedule this idle function, since we've now done
+         * everything we can until the innermost gtk_main has quit and
+         * can reschedule us with a chance of actually taking action.
+         */
+        if (inst->idle_fn_scheduled) { /* double-check, just in case */
+            gtk_idle_remove(inst->toplevel_callback_idle_id);
+            inst->idle_fn_scheduled = FALSE;
+        }
+    } else {
+        run_toplevel_callbacks();
+    }
+
+    /*
+     * If we've emptied our toplevel callback queue, unschedule
+     * ourself. Otherwise, leave ourselves pending so we'll be called
+     * again to deal with more callbacks after another round of the
+     * event loop.
+     */
+    if (!toplevel_callback_pending() && inst->idle_fn_scheduled) {
+        gtk_idle_remove(inst->toplevel_callback_idle_id);
+        inst->idle_fn_scheduled = FALSE;
+    }
 
-    gtk_idle_remove(inst->term_exit_idle_id);
     return TRUE;
 }
 
-void notify_remote_exit(void *frontend)
+static void notify_toplevel_callback(void *frontend)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
 
-    inst->term_exit_idle_id = gtk_idle_add(idle_exit_func, inst);
+    if (!inst->idle_fn_scheduled) {
+        inst->toplevel_callback_idle_id =
+            gtk_idle_add(idle_toplevel_callback_func, inst);
+        inst->idle_fn_scheduled = TRUE;
+    }
 }
 
 static gint timer_trigger(gpointer data)
 {
-    long now = GPOINTER_TO_LONG(data);
-    long next;
+    unsigned long now = GPOINTER_TO_LONG(data);
+    unsigned long next, then;
     long ticks;
 
-    if (run_timers(now, &next)) {
-       ticks = next - GETTICKCOUNT();
-       timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger,
+    /*
+     * Destroy the timer we got here on.
+     */
+    if (timer_id) {
+       gtk_timeout_remove(timer_id);
+        timer_id = 0;
+    }
+
+    /*
+     * run_timers() may cause a call to timer_change_notify, in which
+     * case a new timer will already have been set up and left in
+     * timer_id. If it hasn't, and run_timers reports that some timing
+     * still needs to be done, we do it ourselves.
+     */
+    if (run_timers(now, &next) && !timer_id) {
+       then = now;
+       now = GETTICKCOUNT();
+       if (now - then > next - then)
+           ticks = 0;
+       else
+           ticks = next - now;
+       timer_id = gtk_timeout_add(ticks, timer_trigger,
                                   LONG_TO_GPOINTER(next));
     }
 
     /*
-     * Never let a timer resume. If we need another one, we've
-     * asked for it explicitly above.
+     * Returning FALSE means 'don't call this timer again', which
+     * _should_ be redundant given that we removed it above, but just
+     * in case, return FALSE anyway.
      */
     return FALSE;
 }
 
-void timer_change_notify(long next)
+void timer_change_notify(unsigned long next)
 {
     long ticks;
 
@@ -1590,7 +1682,7 @@ void palette_set(void *frontend, int n, int r, int g, int b)
     struct gui_data *inst = (struct gui_data *)frontend;
     if (n >= 16)
        n += 256 - 16;
-    if (n > NALLCOLOURS)
+    if (n >= NALLCOLOURS)
        return;
     real_palette_set(inst, n, r, g, b);
     if (n == 258) {
@@ -1973,28 +2065,12 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
 
     term_do_paste(inst->term);
 
-    if (term_paste_pending(inst->term))
-       inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst);
-
     if (free_list_required)
        XFreeStringList(list);
     if (free_required)
        XFree(text);
 }
 
-gint idle_paste_func(gpointer data)
-{
-    struct gui_data *inst = (struct gui_data *)data;
-
-    if (term_paste_pending(inst->term))
-       term_paste(inst->term);
-    else
-       gtk_idle_remove(inst->term_paste_idle_id);
-
-    return TRUE;
-}
-
-
 void get_clip(void *frontend, wchar_t ** p, int *len)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
@@ -2527,7 +2603,7 @@ GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val)
     return ret;
 }
 
-void modalfatalbox(char *p, ...)
+void modalfatalbox(const char *p, ...)
 {
     va_list ap;
     fprintf(stderr, "FATAL ERROR: ");
@@ -2538,7 +2614,7 @@ void modalfatalbox(char *p, ...)
     exit(1);
 }
 
-void cmdline_error(char *p, ...)
+void cmdline_error(const char *p, ...)
 {
     va_list ap;
     fprintf(stderr, "%s: ", appname);
@@ -2587,6 +2663,13 @@ static void help(FILE *fp) {
     }
 }
 
+static void version(FILE *fp) {
+    if(fprintf(fp, "%s: %s\n", appname, ver) < 0 || fflush(fp) < 0) {
+       perror("output error");
+       exit(1);
+    }
+}
+
 int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
                struct gui_data *inst, Conf *conf)
 {
@@ -2612,7 +2695,7 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
 #define SECOND_PASS_ONLY { if (!do_everything) continue; }
 
     while (--argc > 0) {
-       char *p = *++argv;
+       const char *p = *++argv;
         int ret;
 
        /*
@@ -2796,6 +2879,10 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
            help(stdout);
            exit(0);
 
+       } else if(!strcmp(p, "-version") || !strcmp(p, "--version")) {
+           version(stdout);
+           exit(0);
+
         } else if (!strcmp(p, "-pgpfp")) {
             pgp_fingerprints();
             exit(1);
@@ -2827,87 +2914,73 @@ void uxsel_input_remove(int id) {
     gdk_input_remove(id);
 }
 
-int frontend_net_pending_error_idle_id;
-int frontend_got_net_pending_errors = FALSE;
-gboolean frontend_net_pending_errors(gpointer data)
-{
-    net_pending_errors();
-    gtk_idle_remove(frontend_net_pending_error_idle_id);
-    frontend_got_net_pending_errors = FALSE;
-    return FALSE;
-}
-void frontend_net_error_pending(void)
-{
-    if (!frontend_got_net_pending_errors) {
-        frontend_got_net_pending_errors = TRUE;
-        frontend_net_pending_error_idle_id =
-            gtk_idle_add(frontend_net_pending_errors, NULL);
-    }
-}
-
-void setup_fonts_ucs(struct gui_data *inst)
+char *setup_fonts_ucs(struct gui_data *inst)
 {
     int shadowbold = conf_get_int(inst->conf, CONF_shadowbold);
     int shadowboldoffset = conf_get_int(inst->conf, CONF_shadowboldoffset);
     FontSpec *fs;
-
-    if (inst->fonts[0])
-        unifont_destroy(inst->fonts[0]);
-    if (inst->fonts[1])
-        unifont_destroy(inst->fonts[1]);
-    if (inst->fonts[2])
-        unifont_destroy(inst->fonts[2]);
-    if (inst->fonts[3])
-        unifont_destroy(inst->fonts[3]);
+    unifont *fonts[4];
+    int i;
 
     fs = conf_get_fontspec(inst->conf, CONF_font);
-    inst->fonts[0] = multifont_create(inst->area, fs->name, FALSE, FALSE,
-                                      shadowboldoffset, shadowbold);
-    if (!inst->fonts[0]) {
-       fprintf(stderr, "%s: unable to load font \"%s\"\n", appname,
-               fs->name);
-       exit(1);
+    fonts[0] = multifont_create(inst->area, fs->name, FALSE, FALSE,
+                                shadowboldoffset, shadowbold);
+    if (!fonts[0]) {
+        return dupprintf("unable to load font \"%s\"", fs->name);
     }
 
     fs = conf_get_fontspec(inst->conf, CONF_boldfont);
     if (shadowbold || !fs->name[0]) {
-       inst->fonts[1] = NULL;
+       fonts[1] = NULL;
     } else {
-       inst->fonts[1] = multifont_create(inst->area, fs->name, FALSE, TRUE,
-                                          shadowboldoffset, shadowbold);
-       if (!inst->fonts[1]) {
-           fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname,
-                   fs->name);
-           exit(1);
+       fonts[1] = multifont_create(inst->area, fs->name, FALSE, TRUE,
+                                    shadowboldoffset, shadowbold);
+       if (!fonts[1]) {
+            if (fonts[0])
+                unifont_destroy(fonts[0]);
+           return dupprintf("unable to load bold font \"%s\"", fs->name);
        }
     }
 
     fs = conf_get_fontspec(inst->conf, CONF_widefont);
     if (fs->name[0]) {
-       inst->fonts[2] = multifont_create(inst->area, fs->name, TRUE, FALSE,
-                                          shadowboldoffset, shadowbold);
-       if (!inst->fonts[2]) {
-           fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname,
-                   fs->name);
-           exit(1);
+       fonts[2] = multifont_create(inst->area, fs->name, TRUE, FALSE,
+                                    shadowboldoffset, shadowbold);
+       if (!fonts[2]) {
+            for (i = 0; i < 2; i++)
+                if (fonts[i])
+                    unifont_destroy(fonts[i]);
+            return dupprintf("unable to load wide font \"%s\"", fs->name);
        }
     } else {
-       inst->fonts[2] = NULL;
+       fonts[2] = NULL;
     }
 
     fs = conf_get_fontspec(inst->conf, CONF_wideboldfont);
     if (shadowbold || !fs->name[0]) {
-       inst->fonts[3] = NULL;
+       fonts[3] = NULL;
     } else {
-       inst->fonts[3] = multifont_create(inst->area, fs->name, TRUE, TRUE,
-                                          shadowboldoffset, shadowbold);
-       if (!inst->fonts[3]) {
-           fprintf(stderr, "%s: unable to load wide bold font \"%s\"\n", appname,
-                   fs->name);
-           exit(1);
+       fonts[3] = multifont_create(inst->area, fs->name, TRUE, TRUE,
+                                    shadowboldoffset, shadowbold);
+       if (!fonts[3]) {
+            for (i = 0; i < 3; i++)
+                if (fonts[i])
+                    unifont_destroy(fonts[i]);
+           return dupprintf("unable to load wide bold font \"%s\"", fs->name);
        }
     }
 
+    /*
+     * Now we've got past all the possible error conditions, we can
+     * actually update our state.
+     */
+
+    for (i = 0; i < 4; i++) {
+        if (inst->fonts[i])
+            unifont_destroy(inst->fonts[i]);
+        inst->fonts[i] = fonts[i];
+    }
+
     inst->font_width = inst->fonts[0]->width;
     inst->font_height = inst->fonts[0]->height;
 
@@ -2916,6 +2989,8 @@ void setup_fonts_ucs(struct gui_data *inst)
                                    conf_get_int(inst->conf, CONF_utf8_override),
                                    inst->fonts[0]->public_charset,
                                    conf_get_int(inst->conf, CONF_vtmode));
+
+    return NULL;
 }
 
 void set_geom_hints(struct gui_data *inst)
@@ -2945,7 +3020,7 @@ void reset_terminal_menuitem(GtkMenuItem *item, gpointer data)
     struct gui_data *inst = (struct gui_data *)data;
     term_pwron(inst->term, TRUE);
     if (inst->ldisc)
-       ldisc_send(inst->ldisc, NULL, 0, 0);
+       ldisc_echoedit_update(inst->ldisc);
 }
 
 void copy_all_menuitem(GtkMenuItem *item, gpointer data)
@@ -2985,7 +3060,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
        4, 12, 5, 13, 6, 14, 7, 15
     };
     struct gui_data *inst = (struct gui_data *)data;
-    char *title = dupcat(appname, " Reconfiguration", NULL);
+    char *title;
     Conf *oldconf, *newconf;
     int i, j, need_size;
 
@@ -2996,6 +3071,8 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
     else
       inst->reconfiguring = TRUE;
 
+    title = dupcat(appname, " Reconfiguration", NULL);
+
     oldconf = inst->conf;
     newconf = conf_copy(inst->conf);
 
@@ -3009,9 +3086,10 @@ 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_configure(inst->ldisc, inst->conf);
-        if (inst->ldisc)
-           ldisc_send(inst->ldisc, NULL, 0, 0);
+        if (inst->ldisc) {
+            ldisc_configure(inst->ldisc, inst->conf);
+            ldisc_echoedit_update(inst->ldisc);
+        }
         /* Pass new config data to the terminal */
         term_reconfig(inst->term, inst->conf);
         /* Pass new config data to the back end */
@@ -3044,7 +3122,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
                 * repaint the space in between the window border
                 * and the text area.
                 */
-               if (i == 258) {
+               if (ww[i] == 258) {
                    set_window_background(inst);
                    draw_backing_rect(inst);
                }
@@ -3081,6 +3159,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
          * Redo the whole tangled fonts and Unicode mess if
          * necessary.
          */
+        need_size = FALSE;
         if (strcmp(conf_get_fontspec(oldconf, CONF_font)->name,
                   conf_get_fontspec(newconf, CONF_font)->name) ||
            strcmp(conf_get_fontspec(oldconf, CONF_boldfont)->name,
@@ -3099,10 +3178,21 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
            conf_get_int(newconf, CONF_shadowbold) ||
            conf_get_int(oldconf, CONF_shadowboldoffset) !=
            conf_get_int(newconf, CONF_shadowboldoffset)) {
-            setup_fonts_ucs(inst);
-            need_size = 1;
-        } else
-            need_size = 0;
+            char *errmsg = setup_fonts_ucs(inst);
+            if (errmsg) {
+                char *msgboxtext =
+                    dupprintf("Could not change fonts in terminal window: %s\n",
+                              errmsg);
+                messagebox(inst->window, "Font setup error", msgboxtext,
+                           string_width("Could not change fonts in terminal window:"),
+                           "OK", 'o', +1, 1,
+                           NULL);
+                sfree(msgboxtext);
+                sfree(errmsg);
+            } else {
+                need_size = TRUE;
+            }
+        }
 
         /*
          * Resize the window.
@@ -3192,6 +3282,7 @@ void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...)
     pid = fork();
     if (pid < 0) {
        perror("fork");
+        sfree(args);
        return;
     }
 
@@ -3225,6 +3316,7 @@ void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...)
 
     } else {
        int status;
+        sfree(args);
        waitpid(pid, &status, 0);
     }
 
@@ -3266,7 +3358,7 @@ void dup_session_menuitem(GtkMenuItem *item, gpointer gdata)
     }
 
     sprintf(option, "---[%d,%d]", pipefd[0], size);
-    fcntl(pipefd[0], F_SETFD, 0);
+    noncloexec(pipefd[0]);
     fork_and_exec_self(inst, pipefd[1], option, NULL);
     close(pipefd[0]);
 
@@ -3329,6 +3421,8 @@ int read_dupsession_data(struct gui_data *inst, Conf *conf, char *arg)
        }
     }
 
+    sfree(data);
+
     return 0;
 }
 
@@ -3559,6 +3653,8 @@ int pt_main(int argc, char **argv)
     inst->busy_status = BUSY_NOT;
     inst->conf = conf_new();
     inst->wintitle = inst->icontitle = NULL;
+    inst->quit_fn_scheduled = FALSE;
+    inst->idle_fn_scheduled = FALSE;
 
     /* defer any child exit handling until we're ready to deal with
      * it */
@@ -3582,7 +3678,7 @@ int pt_main(int argc, char **argv)
     if (argc > 1 && !strncmp(argv[1], "---", 3)) {
        read_dupsession_data(inst, inst->conf, argv[1]);
        /* Splatter this argument so it doesn't clutter a ps listing */
-       memset(argv[1], 0, strlen(argv[1]));
+       smemclr(argv[1], strlen(argv[1]));
     } else {
        /* By default, we bring up the config dialog, rather than launching
         * a session. This gets set to TRUE if something happens to change
@@ -3615,7 +3711,13 @@ int pt_main(int argc, char **argv)
     inst->imc = gtk_im_multicontext_new();
 #endif
 
-    setup_fonts_ucs(inst);
+    {
+        char *errmsg = setup_fonts_ucs(inst);
+        if (errmsg) {
+            fprintf(stderr, "%s: %s\n", appname, errmsg);
+            exit(1);
+        }
+    }
     init_cutbuffers();
 
     inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -3809,6 +3911,8 @@ int pt_main(int argc, char **argv)
 
     inst->eventlogstuff = eventlogstuff_new();
 
+    request_callback_notifications(notify_toplevel_callback, inst);
+
     inst->term = term_init(inst->conf, &inst->ucsdata, inst);
     inst->logctx = log_init(inst, inst->conf);
     term_provide_logctx(inst->term, inst->logctx);
@@ -3820,7 +3924,7 @@ int pt_main(int argc, char **argv)
 
     start_backend(inst);
 
-    ldisc_send(inst->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */
+    ldisc_echoedit_update(inst->ldisc);     /* cause ldisc to notice changes */
 
     /* now we're reday to deal with the child exit handler being
      * called */