1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Don't implicitly load a session if Session pane not active.

If you select an entry in the saved sessions list box, but without
double-clicking to actually load it, and then you hit OK, the config-
box code will automatically load it. That just saves one click in a
common situation.

But in order to load that session, the config-box system first has to
ask the list-box control _which_ session is selected. On Windows, this
causes an assertion failure if the user has switched away from the
Session panel to some other panel of the config box, because when the
list box isn't on screen, its Windows control object is actually
destroyed.

I think a sensible answer is that we shouldn't be doing that implicit
load behaviour in any case if the list box isn't _visible_: silently
loading and launching a session someone selected a lot of UI actions
ago wasn't really the point. So now I make that behaviour only happen
when the list box (i.e. the Session panel) _is_ visible. That should
prevent the assertion failure on Windows, but the UI effect is cross-
platform, applying even on GTK where the control objects for invisible
panels persist and so the assertion failure didn't happen. I think
it's a reasonable UI change to make globally.

In order to implement it, I've had to invent a new query function so
that config.c can tell whether a given control is visible. In order to
do that on GTK, I had to give each control a pointer to the 'selparam'
structure describing its config-box pane, so that query function could
check it against the current one - and in order to do _that_, I had to
first arrange that those 'selparam' structures have stable addresses
from the moment they're first created, which meant adding a layer of
indirection so that the array of them in the top-level dlgparam
structure is now an array of _pointers_ rather than of actual structs.
(That way, realloc half way through config box creation can't
invalidate the important pointer values.)
This commit is contained in:
Simon Tatham 2019-06-29 17:12:47 +01:00
parent be0b7cee83
commit e790adec4a
5 changed files with 74 additions and 31 deletions

View File

@ -780,7 +780,7 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg,
* valid host name in it, then load it and go.
*/
if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
!conf_launchable(conf)) {
!conf_launchable(conf) && dlg_is_visible(ssd->listbox, dlg)) {
Conf *conf2 = conf_new();
bool mbl = false;
if (!load_selected_session(ssd, dlg, conf2, &mbl)) {

View File

@ -585,6 +585,10 @@ void dlg_label_change(union control *ctrl, dlgparam *dp, char const *text);
* functionality on it!
*/
union control *dlg_last_focused(union control *ctrl, dlgparam *dp);
/*
* Find out whether a particular control is currently visible.
*/
bool dlg_is_visible(union control *ctrl, dlgparam *dp);
/*
* During event processing, you might well want to give an error
* indication to the user. dlg_beep() is a quick and easy generic

View File

@ -175,6 +175,7 @@ void dlg_coloursel_start(union control *ctrl, void *dlg,
bool dlg_coloursel_results(union control *ctrl, void *dlg,
int *r, int *g, int *b) { return false; }
void dlg_refresh(union control *ctrl, void *dlg) { }
bool dlg_is_visible(union control *ctrl, dlgparam *dp) { return false; }
const char *const appname = "FuZZterm";
const int ngsslibs = 0;

View File

@ -51,6 +51,8 @@ struct Shortcuts {
struct Shortcut sc[128];
};
struct selparam;
struct uctrl {
union control *ctrl;
GtkWidget *toplevel;
@ -71,6 +73,7 @@ struct uctrl {
GtkWidget *text; /* for text */
GtkWidget *label; /* for dlg_label_change */
GtkAdjustment *adj; /* for the scrollbar in a list box */
struct selparam *sp; /* which switchable pane of the box we're in */
guint entrysig;
guint textsig;
int nclicks;
@ -94,8 +97,9 @@ struct dlgparam {
int ntreeitems;
#else
size_t nselparams;
struct selparam *selparams;
struct selparam **selparams;
#endif
struct selparam *curr_panel;
struct controlbox *ctrlbox;
int retval;
post_dialog_fn_t after;
@ -206,6 +210,7 @@ static void dlg_init(struct dlgparam *dp)
dp->treeitems = NULL;
dp->currtreeitem = NULL;
#endif
dp->curr_panel = NULL;
dp->flags = 0;
dp->currfocus = NULL;
}
@ -1843,8 +1848,9 @@ static void label_sizealloc(GtkWidget *widget, GtkAllocation *alloc,
* non-NULL, all buttons created will be default-capable (so they
* have extra space round them for the default highlight).
*/
GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs,
struct controlset *s, GtkWindow *win)
GtkWidget *layout_ctrls(
struct dlgparam *dp, struct selparam *sp, struct Shortcuts *scs,
struct controlset *s, GtkWindow *win)
{
Columns *cols;
GtkWidget *ret;
@ -1903,6 +1909,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs,
}
uc = snew(struct uctrl);
uc->sp = sp;
uc->ctrl = ctrl;
uc->buttons = NULL;
uc->entry = NULL;
@ -2523,7 +2530,7 @@ struct selparam {
static void treeselection_changed(GtkTreeSelection *treeselection,
gpointer data)
{
struct selparam *sps = (struct selparam *)data, *sp;
struct selparam **sps = (struct selparam **)data, *sp;
GtkTreeModel *treemodel;
GtkTreeIter treeiter;
gint spindex;
@ -2533,11 +2540,12 @@ static void treeselection_changed(GtkTreeSelection *treeselection,
return;
gtk_tree_model_get(treemodel, &treeiter, TREESTORE_PARAMS, &spindex, -1);
sp = &sps[spindex];
sp = sps[spindex];
page_num = gtk_notebook_page_num(sp->panels, sp->panel);
gtk_notebook_set_current_page(sp->panels, page_num);
sp->dp->curr_panel = sp;
dlg_refresh(NULL, sp->dp);
sp->dp->shortcuts = &sp->shortcuts;
@ -2551,6 +2559,7 @@ static void treeitem_sel(GtkItem *item, gpointer data)
page_num = gtk_notebook_page_num(sp->panels, sp->panel);
gtk_notebook_set_page(sp->panels, page_num);
sp->dp->curr_panel = sp;
dlg_refresh(NULL, sp->dp);
sp->dp->shortcuts = &sp->shortcuts;
@ -2558,6 +2567,17 @@ static void treeitem_sel(GtkItem *item, gpointer data)
}
#endif
bool dlg_is_visible(union control *ctrl, dlgparam *dp)
{
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
/*
* A control is visible if it belongs to _no_ notebook page (i.e.
* it's one of the config-box-global buttons like Load or About),
* or if it belongs to the currently selected page.
*/
return uc->sp == NULL || uc->sp == dp->curr_panel;
}
#if !GTK_CHECK_VERSION(2,0,0)
static bool tree_grab_focus(struct dlgparam *dp)
{
@ -2879,9 +2899,9 @@ void initial_treeview_collapse(struct dlgparam *dp, GtkWidget *tree)
*/
int i;
for (i = 0; i < dp->nselparams; i++)
if (dp->selparams[i].depth >= 2)
if (dp->selparams[i]->depth >= 2)
gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree),
dp->selparams[i].treepath);
dp->selparams[i]->treepath);
}
#endif
@ -2917,7 +2937,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
struct dlgparam *dp;
struct Shortcuts scs;
struct selparam *selparams = NULL;
struct selparam **selparams = NULL;
size_t nselparams = 0, selparamsize = 0;
dp = snew(struct dlgparam);
@ -2991,7 +3011,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
GtkWidget *w;
if (!*s->pathname) {
w = layout_ctrls(dp, &scs, s, GTK_WINDOW(window));
w = layout_ctrls(dp, NULL, &scs, s, GTK_WINDOW(window));
our_dialog_set_action_area(GTK_WINDOW(window), w);
} else {
@ -3031,6 +3051,9 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
gtk_widget_show(panelvbox);
gtk_notebook_append_page(GTK_NOTEBOOK(panels), panelvbox,
NULL);
struct selparam *sp = snew(struct selparam);
if (first) {
gint page_num;
@ -3038,13 +3061,16 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
panelvbox);
gtk_notebook_set_current_page(GTK_NOTEBOOK(panels),
page_num);
dp->curr_panel = sp;
}
sgrowarray(selparams, selparamsize, nselparams);
selparams[nselparams].dp = dp;
selparams[nselparams].panels = GTK_NOTEBOOK(panels);
selparams[nselparams].panel = panelvbox;
selparams[nselparams].shortcuts = scs; /* structure copy */
selparams[nselparams] = sp;
sp->dp = dp;
sp->panels = GTK_NOTEBOOK(panels);
sp->panel = panelvbox;
sp->shortcuts = scs; /* structure copy */
assert(j-1 < level);
@ -3063,11 +3089,10 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
-1);
treeiterlevels[j] = treeiter;
selparams[nselparams].depth = j;
sp->depth = j;
if (j > 0) {
selparams[nselparams].treepath =
gtk_tree_model_get_path(GTK_TREE_MODEL(treestore),
&treeiterlevels[j-1]);
sp->treepath = gtk_tree_model_get_path(
GTK_TREE_MODEL(treestore), &treeiterlevels[j-1]);
/*
* We are going to collapse all tree branches
* at depth greater than 2, but not _yet_; see
@ -3075,10 +3100,9 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
* gtk_tree_view_collapse_row below.
*/
gtk_tree_view_expand_row(GTK_TREE_VIEW(tree),
selparams[nselparams].treepath,
false);
sp->treepath, false);
} else {
selparams[nselparams].treepath = NULL;
sp->treepath = NULL;
}
#else
treeitem = gtk_tree_item_new_with_label(c);
@ -3109,14 +3133,15 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
if (first)
gtk_tree_select_child(GTK_TREE(tree), treeitem);
selparams[nselparams].treeitem = treeitem;
sp->treeitem = treeitem;
#endif
level = j+1;
nselparams++;
}
w = layout_ctrls(dp, &selparams[nselparams-1].shortcuts, s, NULL);
w = layout_ctrls(dp, selparams[nselparams-1],
&selparams[nselparams-1]->shortcuts, s, NULL);
gtk_box_pack_start(GTK_BOX(panelvbox), w, false, false, 0);
gtk_widget_show(w);
}
@ -3178,7 +3203,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf,
dp->data = conf;
dlg_refresh(NULL, dp);
dp->shortcuts = &selparams[0].shortcuts;
dp->shortcuts = &selparams[0]->shortcuts;
#if !GTK_CHECK_VERSION(2,0,0)
dp->currtreeitem = dp->treeitems[0];
#endif
@ -3239,9 +3264,11 @@ static void dlgparam_destroy(GtkWidget *widget, gpointer data)
ctrl_free_box(dp->ctrlbox);
#if GTK_CHECK_VERSION(2,0,0)
if (dp->selparams) {
for (size_t i = 0; i < dp->nselparams; i++)
if (dp->selparams[i].treepath)
gtk_tree_path_free(dp->selparams[i].treepath);
for (size_t i = 0; i < dp->nselparams; i++) {
if (dp->selparams[i]->treepath)
gtk_tree_path_free(dp->selparams[i]->treepath);
sfree(dp->selparams[i]);
}
sfree(dp->selparams);
}
#endif
@ -3341,10 +3368,10 @@ GtkWidget *create_message_box(
window = our_dialog_new();
gtk_window_set_title(GTK_WINDOW(window), title);
w0 = layout_ctrls(dp, &scs, s0, GTK_WINDOW(window));
w0 = layout_ctrls(dp, NULL, &scs, s0, GTK_WINDOW(window));
our_dialog_set_action_area(GTK_WINDOW(window), w0);
gtk_widget_show(w0);
w1 = layout_ctrls(dp, &scs, s1, GTK_WINDOW(window));
w1 = layout_ctrls(dp, NULL, &scs, s1, GTK_WINDOW(window));
gtk_container_set_border_width(GTK_CONTAINER(w1), 10);
gtk_widget_set_size_request(w1, minwid+20, -1);
our_dialog_add_to_content_area(GTK_WINDOW(window), w1, true, true, 0);
@ -3911,10 +3938,10 @@ void showeventlog(eventlog_stuff *es, void *parentwin)
title = dupcat(appname, " Event Log", (const char *)NULL);
gtk_window_set_title(GTK_WINDOW(window), title);
sfree(title);
w0 = layout_ctrls(&es->dp, &es->scs, s0, GTK_WINDOW(window));
w0 = layout_ctrls(&es->dp, NULL, &es->scs, s0, GTK_WINDOW(window));
our_dialog_set_action_area(GTK_WINDOW(window), w0);
gtk_widget_show(w0);
w1 = layout_ctrls(&es->dp, &es->scs, s1, GTK_WINDOW(window));
w1 = layout_ctrls(&es->dp, NULL, &es->scs, s1, GTK_WINDOW(window));
gtk_container_set_border_width(GTK_CONTAINER(w1), 10);
gtk_widget_set_size_request(w1, 20 + string_width
("LINE OF TEXT GIVING WIDTH OF EVENT LOG IS "

View File

@ -2067,6 +2067,17 @@ static struct winctrl *dlg_findbyctrl(struct dlgparam *dp, union control *ctrl)
return NULL;
}
bool dlg_is_visible(union control *ctrl, dlgparam *dp)
{
/*
* In this implementation of the dialog box, we physically
* uncreate controls that aren't in a visible panel of the config
* box. So we can tell if a control is visible just by checking if
* it _exists_.
*/
return dlg_findbyctrl(dp, ctrl) != NULL;
}
void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int whichbutton)
{
struct winctrl *c = dlg_findbyctrl(dp, ctrl);