Event handling in the GTK dialog engine is now basically present and
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 15 Mar 2003 15:50:42 +0000 (15:50 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 15 Mar 2003 15:50:42 +0000 (15:50 +0000)
correct. All the callbacks are getting called, all the dialog
actions are working (the port forwarding, colour and charclass
configurers are all completely functional), file, font and colour
selectors happen, and it's all looking pretty cool.

git-svn-id: svn://svn.tartarus.org/sgt/putty@2938 cda61777-01e9-0310-a592-d414129be87e

unix/gtkdlg.c

index 2b1f136..d48c422 100644 (file)
@@ -5,13 +5,24 @@
 /*
  * TODO:
  * 
- *  - event handling, in general!
- * 
  *  - keyboard stuff
  *     + accelerators
- *     + tab order
  *     + default button
  * 
+ *  - focus stuff
+ *     + `last focused' for nasty sessionsaver hack
+ *     + set focus into a sensible control to start with
+ *     + perhaps we need uc->primary as the right widget to
+ *       forcibly focus?
+ * 
+ *  - dlg_error_msg
+ * 
+ *  - must return a value from the dialog box!
+ * 
+ *  - font selection hiccup: the default `fixed' is not
+ *    automatically translated into its expanded XLFD form when the
+ *    font selector is started. It should be.
+ * 
  *  - cosmetics:
  *     + can't we _somehow_ have less leading between radio buttons?
  *     + wrapping text widgets, the horror, the horror
 
 #include "putty.h"
 #include "dialog.h"
+#include "tree234.h"
+
+struct uctrl {
+    union control *ctrl;
+    GtkWidget *toplevel;
+    void *privdata;
+    int privdata_needs_free;
+    GtkWidget **buttons; int nbuttons; /* for radio buttons */
+    GtkWidget *entry;         /* for editbox, combobox, filesel, fontsel */
+    GtkWidget *list;         /* for combobox, listbox */
+    GtkWidget *menu;         /* for optionmenu (==droplist) */
+    GtkWidget *optmenu;              /* also for optionmenu */
+    GtkWidget *text;         /* for text */
+};
+
+struct dlgparam {
+    tree234 *byctrl, *bywidget;
+    void *data;
+    struct { unsigned char r, g, b, ok; } coloursel_result;   /* 0-255 */
+    /* `flags' are set to indicate when a GTK signal handler is being called
+     * due to automatic processing and should not flag a user event. */
+    int flags;
+};
+#define FLAG_UPDATING_COMBO_LIST 1
+
+/*
+ * Forward references.
+ */
+static void listitem_button(GtkWidget *item, GdkEventButton *event,
+                           gpointer data);
+static void menuitem_activate(GtkMenuItem *item, gpointer data);
+static void coloursel_ok(GtkButton *button, gpointer data);
+static void coloursel_cancel(GtkButton *button, gpointer data);
+
+static int uctrl_cmp_byctrl(void *av, void *bv)
+{
+    struct uctrl *a = (struct uctrl *)av;
+    struct uctrl *b = (struct uctrl *)bv;
+    if (a->ctrl < b->ctrl)
+       return -1;
+    else if (a->ctrl > b->ctrl)
+       return +1;
+    return 0;
+}
+
+static int uctrl_cmp_byctrl_find(void *av, void *bv)
+{
+    union control *a = (union control *)av;
+    struct uctrl *b = (struct uctrl *)bv;
+    if (a < b->ctrl)
+       return -1;
+    else if (a > b->ctrl)
+       return +1;
+    return 0;
+}
+
+static int uctrl_cmp_bywidget(void *av, void *bv)
+{
+    struct uctrl *a = (struct uctrl *)av;
+    struct uctrl *b = (struct uctrl *)bv;
+    if (a->toplevel < b->toplevel)
+       return -1;
+    else if (a->toplevel > b->toplevel)
+       return +1;
+    return 0;
+}
+
+static int uctrl_cmp_bywidget_find(void *av, void *bv)
+{
+    GtkWidget *a = (GtkWidget *)av;
+    struct uctrl *b = (struct uctrl *)bv;
+    if (a < b->toplevel)
+       return -1;
+    else if (a > b->toplevel)
+       return +1;
+    return 0;
+}
+
+static void dlg_init(struct dlgparam *dp)
+{
+    dp->byctrl = newtree234(uctrl_cmp_byctrl);
+    dp->bywidget = newtree234(uctrl_cmp_bywidget);
+    dp->coloursel_result.ok = FALSE;
+}
+
+static void dlg_cleanup(struct dlgparam *dp)
+{
+    struct uctrl *uc;
+
+    freetree234(dp->byctrl);          /* doesn't free the uctrls inside */
+    while ( (uc = index234(dp->bywidget, 0)) != NULL) {
+       del234(dp->bywidget, uc);
+       if (uc->privdata_needs_free)
+           sfree(uc->privdata);
+       sfree(uc->buttons);
+       sfree(uc);
+    }
+    freetree234(dp->bywidget);
+}
+
+static void dlg_add_uctrl(struct dlgparam *dp, struct uctrl *uc)
+{
+    add234(dp->byctrl, uc);
+    add234(dp->bywidget, uc);
+}
+
+static struct uctrl *dlg_find_byctrl(struct dlgparam *dp, union control *ctrl)
+{
+    return find234(dp->byctrl, ctrl, uctrl_cmp_byctrl_find);
+}
+
+static struct uctrl *dlg_find_bywidget(struct dlgparam *dp, GtkWidget *w)
+{
+    struct uctrl *ret = NULL;
+    do {
+       ret = find234(dp->bywidget, w, uctrl_cmp_bywidget_find);
+       if (ret)
+           return ret;
+       w = w->parent;
+    } while (w);
+    return ret;
+}
 
 void *dlg_get_privdata(union control *ctrl, void *dlg)
 {
-    return NULL;                      /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    return uc->privdata;
 }
 
 void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    uc->privdata = ptr;
+    uc->privdata_needs_free = FALSE;
 }
 
 void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
 {
-    return NULL;                      /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    uc->privdata = smalloc(size);
+    uc->privdata_needs_free = FALSE;
+    return uc->privdata;
 }
 
 union control *dlg_last_focused(void *dlg)
 {
+    struct dlgparam *dp = (struct dlgparam *)dlg;
     return NULL;                       /* FIXME */
 }
 
-void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton)
+void dlg_radiobutton_set(union control *ctrl, void *dlg, int which)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_RADIO);
+    assert(uc->buttons != NULL);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->buttons[which]), TRUE);
 }
 
 int dlg_radiobutton_get(union control *ctrl, void *dlg)
 {
-    return 0;                          /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    int i;
+
+    assert(uc->ctrl->generic.type == CTRL_RADIO);
+    assert(uc->buttons != NULL);
+    for (i = 0; i < uc->nbuttons; i++)
+       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc->buttons[i])))
+           return i;
+    return 0;                         /* got to return something */
 }
 
 void dlg_checkbox_set(union control *ctrl, void *dlg, int checked)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_CHECKBOX);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->toplevel), checked);
 }
 
 int dlg_checkbox_get(union control *ctrl, void *dlg)
 {
-    return 0;                          /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_CHECKBOX);
+    return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc->toplevel));
 }
 
 void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX);
+    assert(uc->entry != NULL);
+    gtk_entry_set_text(GTK_ENTRY(uc->entry), text);
 }
 
 void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX);
+    assert(uc->entry != NULL);
+    strncpy(buffer, gtk_entry_get_text(GTK_ENTRY(uc->entry)),
+           length);
+    buffer[length-1] = '\0';
+}
+
+static void container_remove_and_destroy(GtkWidget *w, gpointer data)
+{
+    GtkContainer *cont = GTK_CONTAINER(data);
+    /* gtk_container_remove will unref the widget for us; we need not. */
+    gtk_container_remove(cont, w);
 }
 
 /* The `listbox' functions can also apply to combo boxes. */
 void dlg_listbox_clear(union control *ctrl, void *dlg)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    GtkContainer *cont;
+
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
+          uc->ctrl->generic.type == CTRL_LISTBOX);
+    assert(uc->menu != NULL || uc->list != NULL);
+
+    cont = (uc->menu ? GTK_CONTAINER(uc->menu) : GTK_CONTAINER(uc->list));
+
+    gtk_container_foreach(cont, container_remove_and_destroy, cont);
 }
 
 void dlg_listbox_del(union control *ctrl, void *dlg, int index)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
+          uc->ctrl->generic.type == CTRL_LISTBOX);
+    assert(uc->menu != NULL || uc->list != NULL);
+
+    if (uc->menu) {
+       gtk_container_remove
+           (GTK_CONTAINER(uc->menu),
+            g_list_nth_data(GTK_MENU_SHELL(uc->menu)->children, index));
+    } else {
+       gtk_list_clear_items(GTK_LIST(uc->list), index, index+1);
+    }
 }
 
 void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
 {
-    /* FIXME */
+    dlg_listbox_addwithindex(ctrl, dlg, text, 0);
 }
 
 /*
@@ -108,53 +310,235 @@ void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
 void dlg_listbox_addwithindex(union control *ctrl, void *dlg,
                              char const *text, int id)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
+          uc->ctrl->generic.type == CTRL_LISTBOX);
+    assert(uc->menu != NULL || uc->list != NULL);
+
+    dp->flags |= FLAG_UPDATING_COMBO_LIST;
+
+    if (uc->menu) {
+       /*
+        * List item in a drop-down (but non-combo) list. Tabs are
+        * ignored; we just provide a standard menu item with the
+        * text.
+        */
+       GtkWidget *menuitem = gtk_menu_item_new_with_label(text);
+
+       gtk_container_add(GTK_CONTAINER(uc->menu), menuitem);
+       gtk_widget_show(menuitem);
+
+       gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", (gpointer)id);
+       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
+                          GTK_SIGNAL_FUNC(menuitem_activate), dp);
+    } else if (!uc->entry) {
+       /*
+        * List item in a non-combo-box list box. We make all of
+        * these Columns containing GtkLabels. This allows us to do
+        * the nasty force_left hack irrespective of whether there
+        * are tabs in the thing.
+        */
+       GtkWidget *listitem = gtk_list_item_new();
+       GtkWidget *cols = columns_new(0);
+       gint *percents;
+       int i, ncols;
+
+       /* Count the tabs in the text, and hence determine # of columns. */
+       ncols = 1;
+       for (i = 0; text[i]; i++)
+           if (text[i] == '\t')
+               ncols++;
+
+       assert(ncols <=
+              (uc->ctrl->listbox.ncols ? uc->ctrl->listbox.ncols : 1));
+       percents = smalloc(ncols * sizeof(gint));
+       percents[ncols-1] = 100;
+       for (i = 0; i < ncols-1; i++) {
+           percents[i] = uc->ctrl->listbox.percentages[i];
+           percents[ncols-1] -= percents[i];
+       }
+       columns_set_cols(COLUMNS(cols), ncols, percents);
+       sfree(percents);
+
+       for (i = 0; i < ncols; i++) {
+           int len = strcspn(text, "\t");
+           char *dup = dupprintf("%.*s", len, text);
+           GtkWidget *label;
+
+           text += len;
+           if (*text) text++;
+           label = gtk_label_new(dup);
+           sfree(dup);
+
+           columns_add(COLUMNS(cols), label, i, 1);
+           columns_force_left_align(COLUMNS(cols), label);
+           gtk_widget_show(label);
+       }
+       gtk_container_add(GTK_CONTAINER(listitem), cols);
+       gtk_widget_show(cols);
+       gtk_container_add(GTK_CONTAINER(uc->list), listitem);
+       gtk_widget_show(listitem);
+
+       gtk_signal_connect(GTK_OBJECT(listitem), "button_press_event",
+                          GTK_SIGNAL_FUNC(listitem_button), dp);
+       gtk_object_set_data(GTK_OBJECT(listitem), "user-data", (gpointer)id);
+    } else {
+       /*
+        * List item in a combo-box list, which means the sensible
+        * thing to do is make it a perfectly normal label. Hence
+        * tabs are disregarded.
+        */
+       GtkWidget *listitem = gtk_list_item_new_with_label(text);
+
+       gtk_container_add(GTK_CONTAINER(uc->list), listitem);
+       gtk_widget_show(listitem);
+
+       gtk_object_set_data(GTK_OBJECT(listitem), "user-data", (gpointer)id);
+    }
+
+    dp->flags &= ~FLAG_UPDATING_COMBO_LIST;
 }
 
 int dlg_listbox_getid(union control *ctrl, void *dlg, int index)
 {
-    return -1;                         /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    GList *children;
+    GtkObject *item;
+
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
+          uc->ctrl->generic.type == CTRL_LISTBOX);
+    assert(uc->menu != NULL || uc->list != NULL);
+
+    children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu :
+                                                   uc->list));
+    item = GTK_OBJECT(g_list_nth_data(children, index));
+
+    return (int)gtk_object_get_data(GTK_OBJECT(item), "user-data");
 }
 
 /* dlg_listbox_index returns <0 if no single element is selected. */
 int dlg_listbox_index(union control *ctrl, void *dlg)
 {
-    return -1;                         /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    GList *children;
+    GtkWidget *item, *activeitem;
+    int i;
+    int selected = -1;
+
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
+          uc->ctrl->generic.type == CTRL_LISTBOX);
+    assert(uc->menu != NULL || uc->list != NULL);
+
+    if (uc->menu)
+       activeitem = gtk_menu_get_active(GTK_MENU(uc->menu));
+
+    children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu :
+                                                   uc->list));
+    for (i = 0; children!=NULL && (item = GTK_WIDGET(children->data))!=NULL;
+        i++, children = children->next) {
+       if (uc->menu ? activeitem == item :
+           GTK_WIDGET_STATE(item) == GTK_STATE_SELECTED) {
+           if (selected < 0)
+               selected = i;
+           else
+               return -1;
+       }
+    }
+    return selected;
 }
 
 int dlg_listbox_issel(union control *ctrl, void *dlg, int index)
 {
-    return 0;                          /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    GList *children;
+    GtkWidget *item, *activeitem;
+
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
+          uc->ctrl->generic.type == CTRL_LISTBOX);
+    assert(uc->menu != NULL || uc->list != NULL);
+
+    children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu :
+                                                   uc->list));
+    item = GTK_WIDGET(g_list_nth_data(children, index));
+
+    if (uc->menu) {
+       activeitem = gtk_menu_get_active(GTK_MENU(uc->menu));
+       return item == activeitem;
+    } else {
+       return GTK_WIDGET_STATE(item) == GTK_STATE_SELECTED;
+    }
 }
 
 void dlg_listbox_select(union control *ctrl, void *dlg, int index)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+
+    assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
+          uc->ctrl->generic.type == CTRL_LISTBOX);
+    assert(uc->optmenu != NULL || uc->list != NULL);
+
+    if (uc->optmenu) {
+       gtk_option_menu_set_history(GTK_OPTION_MENU(uc->optmenu), index);
+    } else {
+       gtk_list_select_item(GTK_LIST(uc->list), index);
+    }
 }
 
 void dlg_text_set(union control *ctrl, void *dlg, char const *text)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+
+    assert(uc->ctrl->generic.type == CTRL_TEXT);
+    assert(uc->text != NULL);
+
+    gtk_label_set_text(GTK_LABEL(uc->text), text);
 }
 
 void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_FILESELECT);
+    assert(uc->entry != NULL);
+    gtk_entry_set_text(GTK_ENTRY(uc->entry), fn.path);
 }
 
 void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_FILESELECT);
+    assert(uc->entry != NULL);
+    strncpy(fn->path, gtk_entry_get_text(GTK_ENTRY(uc->entry)),
+           lenof(fn->path));
+    fn->path[lenof(fn->path)-1] = '\0';
 }
 
 void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fs)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_FONTSELECT);
+    assert(uc->entry != NULL);
+    gtk_entry_set_text(GTK_ENTRY(uc->entry), fs.name);
 }
 
 void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fs)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    assert(uc->ctrl->generic.type == CTRL_FONTSELECT);
+    assert(uc->entry != NULL);
+    strncpy(fs->name, gtk_entry_get_text(GTK_ENTRY(uc->entry)),
+           lenof(fs->name));
+    fs->name[lenof(fs->name)-1] = '\0';
 }
 
 /*
@@ -164,16 +548,23 @@ void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fs)
  */
 void dlg_update_start(union control *ctrl, void *dlg)
 {
-    /* FIXME */
+    /*
+     * Apparently we can't do this at all in GTK. GtkCList supports
+     * freeze and thaw, but not GtkList. Bah.
+     */
 }
 
 void dlg_update_done(union control *ctrl, void *dlg)
 {
-    /* FIXME */
+    /*
+     * Apparently we can't do this at all in GTK. GtkCList supports
+     * freeze and thaw, but not GtkList. Bah.
+     */
 }
 
 void dlg_set_focus(union control *ctrl, void *dlg)
 {
+    struct dlgparam *dp = (struct dlgparam *)dlg;
     /* FIXME */
 }
 
@@ -184,11 +575,12 @@ void dlg_set_focus(union control *ctrl, void *dlg)
  */
 void dlg_beep(void *dlg)
 {
-    /* FIXME */
+    gdk_beep();
 }
 
 void dlg_error_msg(void *dlg, char *msg)
 {
+    struct dlgparam *dp = (struct dlgparam *)dlg;
     /* FIXME */
 }
 
@@ -199,26 +591,282 @@ void dlg_error_msg(void *dlg, char *msg)
  */
 void dlg_end(void *dlg, int value)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    gtk_main_quit();
+    /* FIXME: don't forget to faff about with returning a value */
 }
 
 void dlg_refresh(union control *ctrl, void *dlg)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc;
+
+    if (ctrl) {
+       if (ctrl->generic.handler != NULL)
+           ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH);
+    } else {
+       int i;
+
+       for (i = 0; (uc = index234(dp->byctrl, i)) != NULL; i++) {
+           assert(uc->ctrl != NULL);
+           if (uc->ctrl->generic.handler != NULL)
+               uc->ctrl->generic.handler(uc->ctrl, dp,
+                                         dp->data, EVENT_REFRESH);
+       }
+    }
 }
 
 void dlg_coloursel_start(union control *ctrl, void *dlg, int r, int g, int b)
 {
-    /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
+    gdouble cvals[4];
+
+    GtkWidget *coloursel =
+       gtk_color_selection_dialog_new("Select a colour");
+    GtkColorSelectionDialog *ccs = GTK_COLOR_SELECTION_DIALOG(coloursel);
+
+    dp->coloursel_result.ok = FALSE;
+
+    gtk_window_set_modal(GTK_WINDOW(coloursel), TRUE);
+    gtk_color_selection_set_opacity(GTK_COLOR_SELECTION(ccs->colorsel), FALSE);
+    cvals[0] = r / 255.0;
+    cvals[1] = g / 255.0;
+    cvals[2] = b / 255.0;
+    cvals[3] = 1.0;                   /* fully opaque! */
+    gtk_color_selection_set_color(GTK_COLOR_SELECTION(ccs->colorsel), cvals);
+
+    gtk_object_set_data(GTK_OBJECT(ccs->ok_button), "user-data",
+                       (gpointer)coloursel);
+    gtk_object_set_data(GTK_OBJECT(ccs->cancel_button), "user-data",
+                       (gpointer)coloursel);
+    gtk_object_set_data(GTK_OBJECT(coloursel), "user-data", (gpointer)uc);
+    gtk_signal_connect(GTK_OBJECT(ccs->ok_button), "clicked",
+                      GTK_SIGNAL_FUNC(coloursel_ok), (gpointer)dp);
+    gtk_signal_connect(GTK_OBJECT(ccs->cancel_button), "clicked",
+                      GTK_SIGNAL_FUNC(coloursel_cancel), (gpointer)dp);
+    gtk_signal_connect_object(GTK_OBJECT(ccs->ok_button), "clicked",
+                             GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                             (gpointer)coloursel);
+    gtk_signal_connect_object(GTK_OBJECT(ccs->cancel_button), "clicked",
+                             GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                             (gpointer)coloursel);
+    gtk_widget_show(coloursel);
 }
 
 int dlg_coloursel_results(union control *ctrl, void *dlg,
                          int *r, int *g, int *b)
 {
-    return 0;                          /* FIXME */
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    if (dp->coloursel_result.ok) {
+       *r = dp->coloursel_result.r;
+       *g = dp->coloursel_result.g;
+       *b = dp->coloursel_result.b;
+       return 1;
+    } else
+       return 0;
 }
 
-/*
+/* ----------------------------------------------------------------------
+ * Signal handlers while the dialog box is active.
+ */
+
+static void button_clicked(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
+}
+
+static void button_toggled(GtkToggleButton *tb, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(tb));
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
+}
+
+static void editbox_changed(GtkEditable *ed, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    if (!(dp->flags & FLAG_UPDATING_COMBO_LIST)) {
+       struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(ed));
+       uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
+    }
+}
+
+static void editbox_lostfocus(GtkWidget *ed, GdkEventFocus *event,
+                             gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(ed));
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_REFRESH);
+}
+
+static void listitem_button(GtkWidget *item, GdkEventButton *event,
+                           gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    if (event->type == GDK_2BUTTON_PRESS ||
+       event->type == GDK_3BUTTON_PRESS) {
+       struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item));
+       uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
+    }
+}
+
+static void list_selchange(GtkList *list, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(list));
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
+}
+
+static void menuitem_activate(GtkMenuItem *item, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    GtkWidget *menushell = GTK_WIDGET(item)->parent;
+    gpointer optmenu = gtk_object_get_data(GTK_OBJECT(menushell), "user-data");
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(optmenu));
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
+}
+
+static void draglist_move(struct dlgparam *dp, struct uctrl *uc, int direction)
+{
+    int index = dlg_listbox_index(uc->ctrl, dp);
+    GList *children = gtk_container_children(GTK_CONTAINER(uc->list));
+    GtkWidget *child;
+
+    if ((index < 0) ||
+       (index == 0 && direction < 0) ||
+       (index == g_list_length(children)-1 && direction > 0)) {
+       gdk_beep();
+       return;
+    }
+
+    child = g_list_nth_data(children, index);
+    gtk_widget_ref(child);
+    gtk_list_clear_items(GTK_LIST(uc->list), index, index+1);
+    children = NULL;
+    children = g_list_append(children, child);
+    gtk_list_insert_items(GTK_LIST(uc->list), children, index + direction);
+    gtk_list_select_item(GTK_LIST(uc->list), index + direction);
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
+}
+
+static void draglist_up(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+    draglist_move(dp, uc, -1);
+}
+
+static void draglist_down(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+    draglist_move(dp, uc, +1);
+}
+
+static void filesel_ok(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    gpointer filesel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+    struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(filesel), "user-data");
+    char *name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel));
+    gtk_entry_set_text(GTK_ENTRY(uc->entry), name);
+}
+
+static void fontsel_ok(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    gpointer fontsel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+    struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(fontsel), "user-data");
+    char *name = gtk_font_selection_dialog_get_font_name
+       (GTK_FONT_SELECTION_DIALOG(fontsel));
+    gtk_entry_set_text(GTK_ENTRY(uc->entry), name);
+}
+
+static void coloursel_ok(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    gpointer coloursel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+    struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(coloursel), "user-data");
+    gdouble cvals[4];
+    gtk_color_selection_get_color
+       (GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(coloursel)->colorsel),
+        cvals);
+    dp->coloursel_result.r = (int) (255 * cvals[0]);
+    dp->coloursel_result.g = (int) (255 * cvals[1]);
+    dp->coloursel_result.b = (int) (255 * cvals[2]);
+    dp->coloursel_result.ok = TRUE;
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK);
+}
+
+static void coloursel_cancel(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    gpointer coloursel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+    struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(coloursel), "user-data");
+    dp->coloursel_result.ok = FALSE;
+    uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK);
+}
+
+static void filefont_clicked(GtkButton *button, gpointer data)
+{
+    struct dlgparam *dp = (struct dlgparam *)data;
+    struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+
+    if (uc->ctrl->generic.type == CTRL_FILESELECT) {
+       GtkWidget *filesel =
+           gtk_file_selection_new(uc->ctrl->fileselect.title);
+       gtk_window_set_modal(GTK_WINDOW(filesel), TRUE);
+       gtk_object_set_data
+           (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "user-data",
+            (gpointer)filesel);
+       gtk_object_set_data(GTK_OBJECT(filesel), "user-data", (gpointer)uc);
+       gtk_signal_connect
+           (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
+            GTK_SIGNAL_FUNC(filesel_ok), (gpointer)dp);
+       gtk_signal_connect_object
+           (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
+            GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)filesel);
+       gtk_signal_connect_object
+           (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button), "clicked",
+            GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)filesel);
+       gtk_widget_show(filesel);
+    }
+
+    if (uc->ctrl->generic.type == CTRL_FONTSELECT) {
+       gchar *spacings[] = { "c", "m", NULL };
+       GtkWidget *fontsel =
+           gtk_font_selection_dialog_new("Select a font");
+       gtk_window_set_modal(GTK_WINDOW(fontsel), TRUE);
+       gtk_font_selection_dialog_set_filter
+           (GTK_FONT_SELECTION_DIALOG(fontsel),
+            GTK_FONT_FILTER_BASE, GTK_FONT_ALL,
+            NULL, NULL, NULL, NULL, spacings, NULL);
+       gtk_font_selection_dialog_set_font_name
+           (GTK_FONT_SELECTION_DIALOG(fontsel),
+            gtk_entry_get_text(GTK_ENTRY(uc->entry)));
+       gtk_object_set_data
+           (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
+            "user-data", (gpointer)fontsel);
+       gtk_object_set_data(GTK_OBJECT(fontsel), "user-data", (gpointer)uc);
+       gtk_signal_connect
+           (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
+            "clicked", GTK_SIGNAL_FUNC(fontsel_ok), (gpointer)dp);
+       gtk_signal_connect_object
+           (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
+            "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy),
+            (gpointer)fontsel);
+       gtk_signal_connect_object
+           (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->cancel_button),
+            "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy),
+            (gpointer)fontsel);
+       gtk_widget_show(fontsel);
+    }
+}
+
+/* ----------------------------------------------------------------------
  * This function does the main layout work: it reads a controlset,
  * it creates the relevant GTK controls, and returns a GtkWidget
  * containing the result. (This widget might be a title of some
@@ -227,7 +875,8 @@ int dlg_coloursel_results(union control *ctrl, void *dlg,
  * definitely a GtkWidget and should probably be added to a
  * GtkVbox.)
  */
-GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
+GtkWidget *layout_ctrls(struct dlgparam *dp, struct controlset *s,
+                       int listitemheight)
 {
     Columns *cols;
     GtkWidget *ret;
@@ -262,8 +911,15 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
      */
     for (i = 0; i < s->ncontrols; i++) {
        union control *ctrl = s->ctrls[i];
+       struct uctrl uc;
         GtkWidget *w = NULL;
 
+       uc.ctrl = ctrl;
+       uc.privdata = NULL;
+       uc.privdata_needs_free = FALSE;
+       uc.buttons = NULL;
+       uc.entry = uc.list = uc.menu = uc.optmenu = uc.text = NULL;
+
         switch (ctrl->generic.type) {
           case CTRL_COLUMNS:
             {
@@ -274,15 +930,21 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
             }
             continue;                  /* no actual control created */
           case CTRL_TABDELAY:
-            /* FIXME: we can do columns_taborder_last easily enough, but
-             * we need to be able to remember which GtkWidget(s) correspond
-             * to ctrl->tabdelay.ctrl. */
+           {
+               struct uctrl *uc = dlg_find_byctrl(dp, ctrl->tabdelay.ctrl);
+               if (uc)
+                   columns_taborder_last(cols, uc->toplevel);
+           }
             continue;                  /* no actual control created */
           case CTRL_BUTTON:
             w = gtk_button_new_with_label(ctrl->generic.label);
+           gtk_signal_connect(GTK_OBJECT(w), "clicked",
+                              GTK_SIGNAL_FUNC(button_clicked), dp);
             break;
           case CTRL_CHECKBOX:
             w = gtk_check_button_new_with_label(ctrl->generic.label);
+           gtk_signal_connect(GTK_OBJECT(w), "toggled",
+                              GTK_SIGNAL_FUNC(button_toggled), dp);
             break;
           case CTRL_RADIO:
             /*
@@ -310,29 +972,42 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
                                  percentages);
                 g_free(percentages);
                 group = NULL;
+
+               uc.nbuttons = ctrl->radio.nbuttons;
+               uc.buttons = smalloc(uc.nbuttons * sizeof(GtkWidget *));
+
                 for (i = 0; i < ctrl->radio.nbuttons; i++) {
                     GtkWidget *b;
                     gint colstart;
 
                     b = (gtk_radio_button_new_with_label
                          (group, ctrl->radio.buttons[i]));
+                   uc.buttons[i] = b;
                     group = gtk_radio_button_group(GTK_RADIO_BUTTON(b));
                     colstart = i % ctrl->radio.ncolumns;
                     columns_add(COLUMNS(w), b, colstart,
                                 (i == ctrl->radio.nbuttons-1 ?
                                  ctrl->radio.ncolumns - colstart : 1));
                     gtk_widget_show(b);
+                   gtk_signal_connect(GTK_OBJECT(b), "toggled",
+                                      GTK_SIGNAL_FUNC(button_toggled), dp);
                 }
             }
             break;
           case CTRL_EDITBOX:
             if (ctrl->editbox.has_list) {
                 w = gtk_combo_new();
+               gtk_combo_set_value_in_list(GTK_COMBO(w), FALSE, TRUE);
+               uc.entry = GTK_COMBO(w)->entry;
+                uc.list = GTK_COMBO(w)->list;
             } else {
                 w = gtk_entry_new();
                 if (ctrl->editbox.password)
                     gtk_entry_set_visibility(GTK_ENTRY(w), FALSE);
+               uc.entry = w;
             }
+           gtk_signal_connect(GTK_OBJECT(uc.entry), "changed",
+                              GTK_SIGNAL_FUNC(editbox_changed), dp);
             /*
              * Edit boxes, for some strange reason, have a minimum
              * width of 150 in GTK 1.2. We don't want this - we'd
@@ -368,6 +1043,8 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
 
                 w = container;
             }
+           gtk_signal_connect(GTK_OBJECT(uc.entry), "focus_out_event",
+                              GTK_SIGNAL_FUNC(editbox_lostfocus), dp);
             break;
           case CTRL_FILESELECT:
           case CTRL_FONTSELECT:
@@ -389,7 +1066,7 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
                     gtk_widget_show(ww);
                 }
 
-                ww = gtk_entry_new();
+                uc.entry = ww = gtk_entry_new();
                 gtk_widget_size_request(ww, &req);
                 gtk_widget_set_usize(ww, 10, req.height);
                 columns_add(COLUMNS(w), ww, 0, 1);
@@ -398,25 +1075,35 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
                 ww = gtk_button_new_with_label(browsebtn);
                 columns_add(COLUMNS(w), ww, 1, 1);
                 gtk_widget_show(ww);
+
+               gtk_signal_connect(GTK_OBJECT(uc.entry), "changed",
+                                  GTK_SIGNAL_FUNC(editbox_changed), dp);
+               gtk_signal_connect(GTK_OBJECT(ww), "clicked",
+                                  GTK_SIGNAL_FUNC(filefont_clicked), dp);
             }
             break;
           case CTRL_LISTBOX:
             if (ctrl->listbox.height == 0) {
-                w = gtk_option_menu_new();
+                uc.optmenu = w = gtk_option_menu_new();
+               uc.menu = gtk_menu_new();
+               gtk_option_menu_set_menu(GTK_OPTION_MENU(w), uc.menu);
+               gtk_object_set_data(GTK_OBJECT(uc.menu), "user-data",
+                                   (gpointer)uc.optmenu);
             } else {
-                GtkWidget *list;
-                list = gtk_list_new();
-                gtk_list_set_selection_mode(GTK_LIST(list),
+                uc.list = gtk_list_new();
+                gtk_list_set_selection_mode(GTK_LIST(uc.list),
                                             (ctrl->listbox.multisel ?
                                              GTK_SELECTION_MULTIPLE :
                                              GTK_SELECTION_SINGLE));
                 w = gtk_scrolled_window_new(NULL, NULL);
                 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(w),
-                                                      list);
+                                                      uc.list);
                 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w),
                                                GTK_POLICY_NEVER,
                                                GTK_POLICY_AUTOMATIC);
-                gtk_widget_show(list);
+                gtk_widget_show(uc.list);
+               gtk_signal_connect(GTK_OBJECT(uc.list), "selection-changed",
+                                  GTK_SIGNAL_FUNC(list_selchange), dp);
 
                 /*
                  * Adjust the height of the scrolled window to the
@@ -431,34 +1118,11 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
                  * upgrades, I'd be grateful.
                  */
                {
-                   int edge = GTK_WIDGET(list)->style->klass->ythickness;
+                   int edge = GTK_WIDGET(uc.list)->style->klass->ythickness;
                     gtk_widget_set_usize(w, 10,
                                          2*edge + (ctrl->listbox.height *
                                                   listitemheight));
                }
-#if 1
-/* here is an example of a percentage-based tabbed list item */
-{ int i; for (i=0; i<10; i++) {
-    GtkWidget *listitem = gtk_list_item_new();
-    GtkWidget *cols = columns_new(4);
-    GtkWidget *label1 = gtk_label_new("left");
-    GtkWidget *label2 = gtk_label_new("right");
-    GList *itemlist;
-    static const gint percents[] = { 50, 50 };
-    columns_set_cols(COLUMNS(cols), 2, percents);
-    columns_add(COLUMNS(cols), label1, 0, 1);
-    columns_force_left_align(COLUMNS(cols), label1);
-    columns_add(COLUMNS(cols), label2, 1, 1);
-    columns_force_left_align(COLUMNS(cols), label2);
-    gtk_widget_show(label1);
-    gtk_widget_show(label2);
-    gtk_widget_show(cols);
-    gtk_container_add(GTK_CONTAINER(listitem), cols);
-    itemlist = g_list_append(NULL, listitem);
-    gtk_list_append_items(GTK_LIST(list), itemlist);
-    gtk_widget_show(listitem);
-} }
-#endif
 
                 if (ctrl->listbox.draglist) {
                     /*
@@ -478,9 +1142,13 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
                     button = gtk_button_new_with_label("Up");
                     columns_add(COLUMNS(cols), button, 1, 1);
                     gtk_widget_show(button);
+                   gtk_signal_connect(GTK_OBJECT(button), "clicked",
+                                      GTK_SIGNAL_FUNC(draglist_up), dp);
                     button = gtk_button_new_with_label("Down");
                     columns_add(COLUMNS(cols), button, 1, 1);
                     gtk_widget_show(button);
+                   gtk_signal_connect(GTK_OBJECT(button), "clicked",
+                                      GTK_SIGNAL_FUNC(draglist_down), dp);
 
                     w = cols;
                 }
@@ -512,16 +1180,23 @@ GtkWidget *layout_ctrls(struct controlset *s, int listitemheight)
             }
             break;
           case CTRL_TEXT:
-            w = gtk_label_new(ctrl->generic.label);
+            uc.text = w = gtk_label_new(ctrl->generic.label);
             gtk_label_set_line_wrap(GTK_LABEL(w), TRUE);
             /* FIXME: deal with wrapping! */
             break;
         }
         if (w) {
+           struct uctrl *ucptr;
+
             columns_add(cols, w,
                         COLUMN_START(ctrl->generic.column),
                         COLUMN_SPAN(ctrl->generic.column));
             gtk_widget_show(w);
+
+           ucptr = smalloc(sizeof(struct uctrl));
+           *ucptr = uc;               /* structure copy */
+           ucptr->toplevel = w;
+           dlg_add_uctrl(dp, ucptr);
         }
     }
 
@@ -555,12 +1230,16 @@ void do_config_box(void)
     GtkTreeItem *treeitemlevels[8];
     GtkTree *treelevels[8];
     Config cfg;
+    struct dlgparam dp;
+    struct sesslist sl;
 
     struct selparam *selparams = NULL;
     int nselparams = 0, selparamsize = 0;
 
     do_defaults(NULL, &cfg);
 
+    dlg_init(&dp);
+
     {
         GtkWidget *listitem = gtk_list_item_new_with_label("foo");
         GtkRequisition req;
@@ -569,8 +1248,10 @@ void do_config_box(void)
         gtk_widget_unref(listitem);
     }
 
+    sl.nsessions = 0;
+
     ctrlbox = ctrl_new_box();
-    setup_config_box(ctrlbox, NULL, FALSE, 0);
+    setup_config_box(ctrlbox, &sl, FALSE, 0);
     unix_setup_config_box(ctrlbox, FALSE);
 
     window = gtk_dialog_new();
@@ -609,7 +1290,7 @@ void do_config_box(void)
     level = 0;
     for (index = 0; index < ctrlbox->nctrlsets; index++) {
        struct controlset *s = ctrlbox->ctrlsets[index];
-       GtkWidget *w = layout_ctrls(s, listitemheight);
+       GtkWidget *w = layout_ctrls(&dp, s, listitemheight);
 
        if (!*s->pathname) {
            gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->action_area),
@@ -693,6 +1374,9 @@ void do_config_box(void)
                           &selparams[index]);
     }
 
+    dp.data = &cfg;
+    dlg_refresh(NULL, &dp);
+
     gtk_widget_show(window);
 
     gtk_signal_connect(GTK_OBJECT(window), "destroy",
@@ -700,6 +1384,7 @@ void do_config_box(void)
 
     gtk_main();
 
+    dlg_cleanup(&dp);
     sfree(selparams);
 }
 
@@ -776,14 +1461,20 @@ int platform_default_i(const char *name, int def)
 FontSpec platform_default_fontspec(const char *name)
 {
     FontSpec ret;
-    *ret.name = '\0';
+    if (!strcmp(name, "Font"))
+       strcpy(ret.name, "fixed");
+    else
+       *ret.name = '\0';
     return ret;
 }
 
 Filename platform_default_filename(const char *name)
 {
     Filename ret;
-    *ret.path = '\0';
+    if (!strcmp(name, "LogFileName"))
+       strcpy(ret.path, "putty.log");
+    else
+       *ret.path = '\0';
     return ret;
 }