Add the ability to allocate extra per-dialog-instance private data
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 8 Mar 2003 11:46:42 +0000 (11:46 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 8 Mar 2003 11:46:42 +0000 (11:46 +0000)
in the portable dialog interface. This has allowed me to remove
`ssd->savedsession' in config.c, which was (I believe) the only
out-of-place piece of per-instance data in the dialog template
stuff. Now we should actually be able to run more than one config
box in the same process at the same time (for platforms that'll find
that useful).

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

config.c
dialog.h
winctrls.c
windlg.c
winstuff.h

index df8134b..961dc7f 100644 (file)
--- a/config.c
+++ b/config.c
@@ -198,10 +198,11 @@ static void sshbug_handler(union control *ctrl, void *dlg,
     }
 }
 
+#define SAVEDSESSION_LEN 2048
+
 struct sessionsaver_data {
     union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
     union control *okbutton, *cancelbutton;
-    char savedsession[2048];
     struct sesslist *sesslist;
 };
 
@@ -211,6 +212,7 @@ struct sessionsaver_data {
  * failure.
  */
 static int load_selected_session(struct sessionsaver_data *ssd,
+                                char *savedsession,
                                 void *dlg, Config *cfg)
 {
     int i = dlg_listbox_index(ssd->listbox, dlg);
@@ -222,11 +224,11 @@ static int load_selected_session(struct sessionsaver_data *ssd,
     isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
     load_settings(ssd->sesslist->sessions[i], !isdef, cfg);
     if (!isdef) {
-       strncpy(ssd->savedsession, ssd->sesslist->sessions[i],
-               sizeof(ssd->savedsession));
-       ssd->savedsession[sizeof(ssd->savedsession)-1] = '\0';
+       strncpy(savedsession, ssd->sesslist->sessions[i],
+               SAVEDSESSION_LEN);
+       savedsession[SAVEDSESSION_LEN-1] = '\0';
     } else {
-       ssd->savedsession[0] = '\0';
+       savedsession[0] = '\0';
     }
     dlg_refresh(NULL, dlg);
     /* Restore the selection, which might have been clobbered by
@@ -241,10 +243,25 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
     Config *cfg = (Config *)data;
     struct sessionsaver_data *ssd =
        (struct sessionsaver_data *)ctrl->generic.context.p;
+    char *savedsession;
+
+    /*
+     * The first time we're called in a new dialog, we must
+     * allocate space to store the current contents of the saved
+     * session edit box (since it must persist even when we switch
+     * panels, but is not part of the Config).
+     */
+    if (!dlg_get_privdata(ssd->editbox, dlg)) {
+       savedsession = (char *)
+           dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
+       savedsession[0] = '\0';
+    } else {
+       savedsession = dlg_get_privdata(ssd->editbox, dlg);
+    }
 
     if (event == EVENT_REFRESH) {
        if (ctrl == ssd->editbox) {
-           dlg_editbox_set(ctrl, dlg, ssd->savedsession);
+           dlg_editbox_set(ctrl, dlg, savedsession);
        } else if (ctrl == ssd->listbox) {
            int i;
            dlg_update_start(ctrl, dlg);
@@ -255,8 +272,8 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
        }
     } else if (event == EVENT_VALCHANGE) {
        if (ctrl == ssd->editbox) {
-           dlg_editbox_get(ctrl, dlg, ssd->savedsession,
-                           sizeof(ssd->savedsession));
+           dlg_editbox_get(ctrl, dlg, savedsession,
+                           SAVEDSESSION_LEN);
        }
     } else if (event == EVENT_ACTION) {
        if (ctrl == ssd->listbox || ctrl == ssd->loadbutton) {
@@ -267,13 +284,13 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
             * double-click on the list box _and_ that session
             * contains a hostname.
             */
-           if (load_selected_session(ssd, dlg, cfg) &&
+           if (load_selected_session(ssd, savedsession, dlg, cfg) &&
                (ctrl == ssd->listbox && cfg->host[0])) {
                dlg_end(dlg, 1);       /* it's all over, and succeeded */
            }
        } else if (ctrl == ssd->savebutton) {
-           int isdef = !strcmp(ssd->savedsession, "Default Settings");
-           if (!ssd->savedsession[0]) {
+           int isdef = !strcmp(savedsession, "Default Settings");
+           if (!savedsession[0]) {
                int i = dlg_listbox_index(ssd->listbox, dlg);
                if (i < 0) {
                    dlg_beep(dlg);
@@ -281,14 +298,14 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
                }
                isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
                if (!isdef) {
-                   strncpy(ssd->savedsession, ssd->sesslist->sessions[i],
-                           sizeof(ssd->savedsession));
-                   ssd->savedsession[sizeof(ssd->savedsession)-1] = '\0';
+                   strncpy(savedsession, ssd->sesslist->sessions[i],
+                           SAVEDSESSION_LEN);
+                   savedsession[SAVEDSESSION_LEN-1] = '\0';
                } else {
-                   ssd->savedsession[0] = '\0';
+                   savedsession[0] = '\0';
                }
            }
-           save_settings(ssd->savedsession, !isdef, cfg);
+           save_settings(savedsession, !isdef, cfg);
            get_sesslist(ssd->sesslist, FALSE);
            get_sesslist(ssd->sesslist, TRUE);
            dlg_refresh(ssd->editbox, dlg);
@@ -313,7 +330,7 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
             */
            if (dlg_last_focused(dlg) == ssd->listbox && !*cfg->host) {
                Config cfg2;
-               if (!load_selected_session(ssd, dlg, &cfg2)) {
+               if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
                    dlg_beep(dlg);
                    return;
                }
@@ -728,7 +745,6 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
        s = ctrl_getset(b, "Session", "savedsessions",
                        "Load, save or delete a stored session");
        ctrl_columns(s, 2, 75, 25);
-       ssd->savedsession[0] = '\0';
        ssd->sesslist = sesslist;
        ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
                                    HELPCTX(session_saved),
index 6b9f5e3..fc1dd41 100644 (file)
--- a/dialog.h
+++ b/dialog.h
@@ -646,6 +646,21 @@ int dlg_coloursel_results(union control *ctrl, void *dlg,
 void dlg_refresh(union control *ctrl, void *dlg);
 
 /*
+ * It's perfectly possible that individual controls might need to
+ * allocate or store per-dialog-instance data, so here's a
+ * mechanism.
+ * 
+ * `dlg_get_privdata' and `dlg_set_privdata' allow the user to get
+ * and set a void * pointer associated with the control in
+ * question. `dlg_alloc_privdata' will allocate memory, store a
+ * pointer to that memory in the private data field, and arrange
+ * for it to be automatically deallocated on dialog cleanup.
+ */
+void *dlg_get_privdata(union control *ctrl, void *dlg);
+void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr);
+void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size);
+
+/*
  * Standard helper functions for reading a controlbox structure.
  */
 
index dc931c8..7e109b3 100644 (file)
@@ -2424,3 +2424,99 @@ int dlg_coloursel_results(union control *ctrl, void *dlg,
     } else
        return 0;
 }
+
+struct perctrl_privdata {
+    union control *ctrl;
+    void *data;
+    int needs_free;
+};
+
+static int perctrl_privdata_cmp(void *av, void *bv)
+{
+    struct perctrl_privdata *a = (struct perctrl_privdata *)av;
+    struct perctrl_privdata *b = (struct perctrl_privdata *)bv;
+    if (a->ctrl < b->ctrl)
+       return -1;
+    else if (a->ctrl > b->ctrl)
+       return +1;
+    return 0;
+}
+
+void dp_init(struct dlgparam *dp)
+{
+    dp->nctrltrees = 0;
+    dp->data = NULL;
+    dp->ended = FALSE;
+    dp->focused = dp->lastfocused = NULL;
+    memset(dp->shortcuts, 0, sizeof(dp->shortcuts));
+    dp->hwnd = NULL;
+    dp->errtitle = NULL;
+    dp->privdata = newtree234(perctrl_privdata_cmp);
+}
+
+void dp_add_tree(struct dlgparam *dp, struct winctrls *wc)
+{
+    assert(dp->nctrltrees < lenof(dp->controltrees));
+    dp->controltrees[dp->nctrltrees++] = wc;
+}
+
+void dp_cleanup(struct dlgparam *dp)
+{
+    struct perctrl_privdata *p;
+
+    if (dp->privdata) {
+       while ( (p = index234(dp->privdata, 0)) != NULL ) {
+           del234(dp->privdata, p);
+           if (p->needs_free)
+               sfree(p->data);
+           sfree(p);
+       }
+       freetree234(dp->privdata);
+       dp->privdata = NULL;
+    }
+}
+
+void *dlg_get_privdata(union control *ctrl, void *dlg)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct perctrl_privdata tmp, *p;
+    tmp.ctrl = ctrl;
+    p = find234(dp->privdata, &tmp, NULL);
+    if (p)
+       return p->data;
+    else
+       return NULL;
+}
+
+void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct perctrl_privdata tmp, *p;
+    tmp.ctrl = ctrl;
+    p = find234(dp->privdata, &tmp, NULL);
+    if (!p) {
+       p = smalloc(sizeof(struct perctrl_privdata));
+       p->ctrl = ctrl;
+       p->needs_free = FALSE;
+       add234(dp->privdata, p);
+    }
+    p->data = ptr;
+}
+
+void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct perctrl_privdata tmp, *p;
+    tmp.ctrl = ctrl;
+    p = find234(dp->privdata, &tmp, NULL);
+    if (!p) {
+       p = smalloc(sizeof(struct perctrl_privdata));
+       p->ctrl = ctrl;
+       p->needs_free = FALSE;
+       add234(dp->privdata, p);
+    }
+    assert(!p->needs_free);
+    p->needs_free = TRUE;
+    p->data = smalloc(size);
+    return p->data;
+}
index ca1890c..ef2a2a4 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -582,16 +582,13 @@ int do_config(void)
     ctrlbox = ctrl_new_box();
     setup_config_box(ctrlbox, &sesslist, FALSE, 0);
     win_setup_config_box(ctrlbox, &dp.hwnd, (help_path != NULL), FALSE);
+    dp_init(&dp);
     winctrl_init(&ctrls_base);
     winctrl_init(&ctrls_panel);
-    dp.controltrees[0] = &ctrls_base;
-    dp.controltrees[1] = &ctrls_panel;
-    dp.nctrltrees = 2;
+    dp_add_tree(&dp, &ctrls_base);
+    dp_add_tree(&dp, &ctrls_panel);
     dp.errtitle = "PuTTY Error";
     dp.data = &cfg;
-    dp.ended = FALSE;
-    dp.lastfocused = NULL;
-    memset(dp.shortcuts, 0, sizeof(dp.shortcuts));
     dp.shortcuts['g'] = TRUE;         /* the treeview: `Cate&gory' */
 
     get_sesslist(&sesslist, TRUE);
@@ -601,8 +598,9 @@ int do_config(void)
     get_sesslist(&sesslist, FALSE);
 
     ctrl_free_box(ctrlbox);
-    winctrl_cleanup(&ctrls_base);
     winctrl_cleanup(&ctrls_panel);
+    winctrl_cleanup(&ctrls_base);
+    dp_cleanup(&dp);
 
     return ret;
 }
@@ -617,16 +615,13 @@ int do_reconfig(HWND hwnd)
     ctrlbox = ctrl_new_box();
     setup_config_box(ctrlbox, NULL, TRUE, cfg.protocol);
     win_setup_config_box(ctrlbox, &dp.hwnd, (help_path != NULL), TRUE);
+    dp_init(&dp);
     winctrl_init(&ctrls_base);
     winctrl_init(&ctrls_panel);
-    dp.controltrees[0] = &ctrls_base;
-    dp.controltrees[1] = &ctrls_panel;
-    dp.nctrltrees = 2;
+    dp_add_tree(&dp, &ctrls_base);
+    dp_add_tree(&dp, &ctrls_panel);
     dp.errtitle = "PuTTY Error";
     dp.data = &cfg;
-    dp.ended = FALSE;
-    dp.lastfocused = NULL;
-    memset(dp.shortcuts, 0, sizeof(dp.shortcuts));
     dp.shortcuts['g'] = TRUE;         /* the treeview: `Cate&gory' */
 
     ret =
@@ -636,6 +631,7 @@ int do_reconfig(HWND hwnd)
     ctrl_free_box(ctrlbox);
     winctrl_cleanup(&ctrls_base);
     winctrl_cleanup(&ctrls_panel);
+    dp_cleanup(&dp);
 
     if (!ret)
        cfg = backup_cfg;              /* structure copy */
index 411fe17..fed920b 100644 (file)
@@ -166,10 +166,11 @@ struct dlgparam {
     char *errtitle;                   /* title of error sub-messageboxes */
     void *data;                               /* data to pass in refresh events */
     union control *focused, *lastfocused; /* which ctrl has focus now/before */
+    char shortcuts[128];              /* track which shortcuts in use */
     int coloursel_wanted;             /* has an event handler asked for
                                        * a colour selector? */
-    char shortcuts[128];              /* track which shortcuts in use */
     struct { unsigned char r, g, b, ok; } coloursel_result;   /* 0-255 */
+    tree234 *privdata;                /* stores per-control private data */
     int ended, endresult;             /* has the dialog been ended? */
 };
 
@@ -283,6 +284,10 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg,
 void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c);
 int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id);
 
+void dp_init(struct dlgparam *dp);
+void dp_add_tree(struct dlgparam *dp, struct winctrls *tree);
+void dp_cleanup(struct dlgparam *dp);
+
 /*
  * Exports from wincfg.c.
  */