From 4e6d40912e43afdde39744815e30dd425a4849d3 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 8 Mar 2003 11:46:42 +0000 Subject: [PATCH] Add the ability to allocate extra per-dialog-instance private data 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 | 52 ++++++++++++++++++++++------------ dialog.h | 15 ++++++++++ winctrls.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ windlg.c | 22 ++++++-------- winstuff.h | 7 ++++- 5 files changed, 160 insertions(+), 32 deletions(-) diff --git a/config.c b/config.c index df8134bd..961dc7fc 100644 --- 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), diff --git a/dialog.h b/dialog.h index 6b9f5e38..fc1dd414 100644 --- 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. */ diff --git a/winctrls.c b/winctrls.c index dc931c88..7e109b38 100644 --- a/winctrls.c +++ b/winctrls.c @@ -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; +} diff --git a/windlg.c b/windlg.c index ca1890c5..ef2a2a4d 100644 --- 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 */ diff --git a/winstuff.h b/winstuff.h index 411fe171..fed920bd 100644 --- a/winstuff.h +++ b/winstuff.h @@ -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. */ -- 2.11.0