From 716479ba4fc7da1f6ce2e4ab36ced3d86f1fffc5 Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Tue, 11 Oct 2016 10:42:44 +0300 Subject: [PATCH] Ticket #3700: fix segfault after switch left panel to info mode. (widget_replace): if new widget cannot take focus, move focus to other widget before widget replacement. In our case, the focused file panel is replaced by Info one. Info panel a) isn't selectable (it never takes focus) and b) uses CWD of current panel. Therefore focus must be moved to other file panel to make it current and correctly set up it's CWD before first draw of Info panel. Signed-off-by: Andrew Borodin --- lib/widget/widget-common.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/widget/widget-common.c b/lib/widget/widget-common.c index e97b526f1..f56328f54 100644 --- a/lib/widget/widget-common.c +++ b/lib/widget/widget-common.c @@ -419,6 +419,7 @@ widget_replace (Widget * old_w, Widget * new_w) { WDialog *h = old_w->owner; gboolean should_focus = FALSE; + GList *holder; if (h->widgets == NULL) return; @@ -426,25 +427,43 @@ widget_replace (Widget * old_w, Widget * new_w) if (h->current == NULL) h->current = h->widgets; + /* locate widget position in the list */ if (old_w == h->current->data) - should_focus = TRUE; + holder = h->current; + else + holder = g_list_find (h->widgets, old_w); + /* if old widget is focused, we should focus the new one... */ + if (widget_get_state (old_w, WST_FOCUSED)) + should_focus = TRUE; + /* ...but if new widget isn't selectable, we cannot focus it */ + if (!widget_get_options (new_w, WOP_SELECTABLE)) + should_focus = FALSE; + + /* if new widget isn't selectable, select other widget before replace */ + if (!should_focus) + { + GList *l; + + for (l = dlg_get_widget_next_of (holder); + !widget_get_options (WIDGET (l->data), WOP_SELECTABLE) + && !widget_get_state (WIDGET (l->data), WST_DISABLED); l = dlg_get_widget_next_of (l)) + ; + + widget_select (WIDGET (l->data)); + } + + /* replace widget */ new_w->owner = h; new_w->id = old_w->id; - - if (should_focus) - h->current->data = new_w; - else - g_list_find (h->widgets, old_w)->data = new_w; + holder->data = new_w; send_message (old_w, NULL, MSG_DESTROY, 0, NULL); send_message (new_w, NULL, MSG_INIT, 0, NULL); if (should_focus) widget_select (new_w); - - /* draw inactive widget */ - if (!widget_get_state (new_w, WST_FOCUSED)) + else widget_redraw (new_w); }