Ticket #4165: MultiSearch_V4.3_final.patch

File MultiSearch_V4.3_final.patch, 65.8 KB (added by psprint, 19 months ago)
  • lib/keybind.c

    From 316c57347747bcf0af6104497c5400f189dd0873 Mon Sep 17 00:00:00 2001
    From: Sebastian Gniazdowski <sgniazdowski@gmail.com>
    Date: Fri, 15 Jan 2021 21:56:49 -0600
    Subject: =?UTF-8?q?Multi=20Search=20=E2=80=93=20an=20AND-chained=20greppin?=
     =?UTF-8?q?g=20of=20any=20listbox?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     lib/keybind.c                  |   1 +
     lib/keybind.h                  |   1 +
     lib/widget.h                   |   2 +
     lib/widget/Makefile.am         |   2 +
     lib/widget/dialog-switch.c     |   3 +-
     lib/widget/filtering_listbox.c | 448 +++++++++++++++++++++++++++++++++
     lib/widget/filtering_listbox.h |  49 ++++
     lib/widget/forwarding_input.c  | 166 ++++++++++++
     lib/widget/forwarding_input.h  |  37 +++
     lib/widget/group.c             |  11 +-
     lib/widget/history.c           |  97 ++++---
     lib/widget/history.h           |   4 +-
     lib/widget/input.c             |  34 ++-
     lib/widget/input_complete.c    |  72 ++++--
     lib/widget/listbox-window.c    |  24 +-
     lib/widget/listbox-window.h    |   4 +-
     lib/widget/listbox.c           |  53 +++-
     lib/widget/listbox.h           |   5 +
     lib/widget/widget-common.c     |   2 +
     lib/widget/widget-common.h     |  10 +-
     src/editor/choosesyntax.c      |   2 +-
     src/editor/editcmd_dialogs.c   |  14 +-
     src/editor/editwidget.c        |   8 +-
     src/file_history.c             |   3 +-
     src/keybind-defaults.c         |   5 +-
     src/selcodepage.c              |   2 +-
     src/usermenu.c                 |   2 +-
     27 files changed, 957 insertions(+), 104 deletions(-)
     create mode 100644 lib/widget/filtering_listbox.c
     create mode 100644 lib/widget/filtering_listbox.h
     create mode 100644 lib/widget/forwarding_input.c
     create mode 100644 lib/widget/forwarding_input.h
    
    diff --git a/lib/keybind.c b/lib/keybind.c
    index abd44d3e2..df3cbf110 100644
    a b static name_keymap_t command_names[] = { 
    9393    ADD_KEYMAP_NAME (SearchContinue), 
    9494    ADD_KEYMAP_NAME (Replace), 
    9595    ADD_KEYMAP_NAME (ReplaceContinue), 
     96    ADD_KEYMAP_NAME (MultiSearch), 
    9697    ADD_KEYMAP_NAME (Help), 
    9798    ADD_KEYMAP_NAME (Shell), 
    9899    ADD_KEYMAP_NAME (Edit), 
  • lib/keybind.h

    diff --git a/lib/keybind.h b/lib/keybind.h
    index af019df09..817158412 100644
    a b enum 
    8282    CK_SearchContinue, 
    8383    CK_Replace, 
    8484    CK_ReplaceContinue, 
     85    CK_MultiSearch, 
    8586    CK_SearchStop, 
    8687    CK_Help, 
    8788    CK_Edit, 
  • lib/widget.h

    diff --git a/lib/widget.h b/lib/widget.h
    index e3bb5cac2..cfe556891 100644
    a b typedef struct WGroup WGroup; 
    3030#include "lib/widget/groupbox.h" 
    3131#include "lib/widget/label.h" 
    3232#include "lib/widget/listbox.h" 
     33#include "lib/widget/filtering_listbox.h" 
    3334#include "lib/widget/menu.h" 
    3435#include "lib/widget/radio.h" 
    3536#include "lib/widget/input.h" 
     37#include "lib/widget/forwarding_input.h" 
    3638#include "lib/widget/listbox-window.h" 
    3739#include "lib/widget/quick.h" 
    3840#include "lib/widget/wtools.h" 
  • lib/widget/Makefile.am

    diff --git a/lib/widget/Makefile.am b/lib/widget/Makefile.am
    index 90f023bbc..9a4616c38 100644
    a b libmcwidget_la_SOURCES = \ 
    1616        history.c history.h \ 
    1717        input.c input.h \ 
    1818        input_complete.c \ 
     19        forwarding_input.c forwarding_input.h \ 
    1920        listbox-window.c listbox-window.h \ 
    2021        listbox.c listbox.h \ 
     22        filtering_listbox.c filtering_listbox.h \ 
    2123        label.c label.h \ 
    2224        menu.c menu.h \ 
    2325        mouse.c mouse.h \ 
  • lib/widget/dialog-switch.c

    diff --git a/lib/widget/dialog-switch.c b/lib/widget/dialog-switch.c
    index 93868b19d..a9a51ce0d 100644
    a b dialog_switch_list (void) 
    241241        else 
    242242            title = g_strdup (""); 
    243243 
    244         listbox_add_item (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, h, FALSE); 
     244        listbox_add_item (LISTBOX (listbox->list), LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, 
     245                          h, FALSE); 
    245246 
    246247        g_free (title); 
    247248    } 
  • new file lib/widget/filtering_listbox.c

    diff --git a/lib/widget/filtering_listbox.c b/lib/widget/filtering_listbox.c
    new file mode 100644
    index 000000000..a4bb8286c
    - +  
     1/* 
     2   A class extending WListbox with dynamic filtering (i.e.: removal) of entries. 
     3 
     4   Copyright (C) <2021> 
     5   Free Software Foundation, Inc. 
     6 
     7   Written by: 
     8   Sebastian Gniazdowski <sgniazdowski@gmail.com>, 2021. 
     9 
     10   This file is part of the Midnight Commander. 
     11 
     12   The Midnight Commander is free software: you can redistribute it 
     13   and/or modify it under the terms of the GNU General Public License as 
     14   published by the Free Software Foundation, either version 3 of the License, 
     15   or (at your option) any later version. 
     16 
     17   The Midnight Commander is distributed in the hope that it will be useful, 
     18   but WITHOUT ANY WARRANTY; without even the implied warranty of 
     19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     20   GNU General Public License for more details. 
     21 
     22   You should have received a copy of the GNU General Public License 
     23   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     24 */ 
     25 
     26/** \file filtering_listbox.c 
     27 *  \brief A WListbox inheriting class that adds dynamic filtering of entries. 
     28 *  \author Sebastian Gniazdowski 
     29 *  \date 2021 
     30 */ 
     31 
     32#include <config.h> 
     33 
     34#include "lib/global.h" 
     35#include "lib/widget.h" 
     36#include "lib/tty/tty.h" 
     37 
     38/*** global variables ****************************************************************************/ 
     39 
     40/*** file scope macro definitions ****************************************************************/ 
     41 
     42/*** file scope type declarations ****************************************************************/ 
     43 
     44/*** file scope variables ************************************************************************/ 
     45 
     46/*** file scope functions ************************************************************************/ 
     47/* --------------------------------------------------------------------------------------------- */ 
     48 
     49static WLEntry * 
     50filt_listbox_shallow_copy_entry (WLEntry * src, gboolean take_ownership) 
     51{ 
     52    WLEntry *copy; 
     53    copy = g_new (WLEntry, 1); 
     54    *copy = *src; 
     55 
     56    /* Who has the ownership of the data? */ 
     57    src->free_text = src->free_text && !take_ownership; 
     58    src->free_data = src->free_data && !take_ownership; 
     59    copy->free_text = copy->free_text && take_ownership; 
     60    copy->free_data = copy->free_data && take_ownership; 
     61 
     62    return copy; 
     63} 
     64 
     65/* --------------------------------------------------------------------------------------------- */ 
     66 
     67static void 
     68filt_listbox_make_one_line_room (WFilteringListbox * sl, int should_add_free_room) 
     69{ 
     70    WListbox *l = LISTBOX (sl); 
     71    Widget *w = WIDGET (l), *owner = WIDGET (WIDGET (w)->owner); 
     72    WRect r_dialog, r_listbox; 
     73    int new_dialog_height, new_dialog_ypos, new_listbox_height, take_give_from_to_owner = 1; 
     74 
     75    /* 
     76     * IF the enlarged dialog won't fit the screen, don't resize it but the listbox instead. 
     77     * Do it also when requested if the listbox is large (for small listboxes always try to 
     78     * enlarge the dialog). 
     79     */ 
     80    if ((sl->resize_strategy == FILT_LIST_DIALOG_AUTO_RESIZE && LINES <= owner->lines + 2) || 
     81        (sl->resize_strategy == FILT_LIST_KEEP_DIALOG_SIZE && owner->lines > 7)) 
     82        take_give_from_to_owner = 0; 
     83 
     84    // Increase the height of the dialog by 1, so that the new input fits. 
     85    if (should_add_free_room) 
     86    { 
     87        new_dialog_height = owner->lines + take_give_from_to_owner; 
     88        new_listbox_height = w->lines + (-1 + take_give_from_to_owner); 
     89        new_dialog_ypos = owner->y - take_give_from_to_owner; 
     90    } 
     91    else 
     92    { 
     93        new_dialog_height = owner->lines - take_give_from_to_owner; 
     94        new_listbox_height = w->lines - (-1 + take_give_from_to_owner); 
     95        new_dialog_ypos = owner->y + take_give_from_to_owner; 
     96    } 
     97    rect_init (&r_dialog, new_dialog_ypos, owner->x, new_dialog_height, owner->cols); 
     98    rect_init (&r_listbox, w->y, w->x, new_listbox_height, w->cols); 
     99    // Doing widget_set_size_rect(w, &r_listbox) causes problems as it invokes 
     100    // drawing of the widget owner. 
     101    send_message (w, NULL, MSG_RESIZE, 0, &r_listbox); 
     102    send_message (owner, NULL, MSG_RESIZE, 0, &r_dialog); 
     103} 
     104 
     105/* --------------------------------------------------------------------------------------------- */ 
     106 
     107static void 
     108filt_listbox_show_multi_search_widget (WFilteringListbox * sl) 
     109{ 
     110    WListbox *l = LISTBOX (sl); 
     111    Widget *w = WIDGET (l), *owner = WIDGET (WIDGET (l)->owner); 
     112    WForwardingInput *multi_search_in; 
     113    int distance_y = owner->y + owner->lines - (w->y + w->lines) + 1; 
     114    int distance_x = w->cols > 40 ? 5 : 1, small = w->cols <= 15 ? 1 : 0; 
     115 
     116    filt_listbox_make_one_line_room (sl, 1); 
     117    multi_search_in = forwarding_input_new (owner->lines - distance_y, distance_x, 
     118                                            input_colors, w->cols - 2 - distance_x + small, "", 
     119                                            "multi_search", INPUT_COMPLETE_NONE, w); 
     120    group_add_widget_autopos (GROUP (owner), multi_search_in, WPOS_KEEP_TOP | WPOS_CENTER_HORZ, 
     121                              NULL); 
     122 
     123    widget_draw (WIDGET (w->owner)); 
     124    widget_draw (w); 
     125    widget_draw (WIDGET (multi_search_in)); 
     126} 
     127 
     128/* --------------------------------------------------------------------------------------------- */ 
     129 
     130static void 
     131filt_listbox_hide_multi_search_widget (WFilteringListbox * sl) 
     132{ 
     133    WListbox *l = LISTBOX (sl); 
     134    Widget *w = WIDGET (sl); 
     135    Widget *in; 
     136    in = widget_find_by_type (WIDGET (WIDGET (l)->owner), forw_input_callback); 
     137    if (in != NULL) 
     138    { 
     139        group_remove_widget (in); 
     140        filt_listbox_make_one_line_room (sl, 0); 
     141        group_select_next_widget (WIDGET (l)->owner); 
     142        // Repainting is needed because some part of the resized dialog can be left on the 
     143        // background. 
     144        if (sl->resize_strategy != FILT_LIST_KEEP_DIALOG_SIZE || w->lines <= 7) 
     145            repaint_screen (); 
     146        widget_draw (WIDGET (w->owner)); 
     147        widget_draw (w); 
     148        widget_destroy (in); 
     149    } 
     150} 
     151 
     152/* --------------------------------------------------------------------------------------------- */ 
     153 
     154/* Return TRUE if given listbox is in WST_FILTER state. */ 
     155static gboolean 
     156filt_listbox_is_filter_state (WFilteringListbox * sl) 
     157{ 
     158    return widget_get_state (WIDGET (sl), WST_FILTER); 
     159} 
     160 
     161/* --------------------------------------------------------------------------------------------- */ 
     162 
     163static void 
     164filt_listbox_filter_list (WFilteringListbox * sl, const char *text) 
     165{ 
     166    WListbox *l = LISTBOX (sl); 
     167    int i, size; 
     168    GList *le; 
     169    char **query_terms; 
     170 
     171    /* 
     172     * Remove the list and allocate a new one. The elements are only shallowly freed because the 
     173     * internal data is still used (and kept in list_keep field). 
     174     */ 
     175    if (l->list != NULL) 
     176        g_queue_free_full (l->list, g_free); 
     177    l->list = g_queue_new (); 
     178 
     179    /* Split the query into space delimeted strings. */ 
     180    query_terms = g_strsplit (text, " ", 10); 
     181 
     182    /* 
     183     * Get the size of the listbox and iterate over it testing each element against ·all· words in  
     184     * query_terms. 
     185     */ 
     186    size = g_queue_get_length (sl->list_keep); 
     187    le = g_queue_peek_head_link (sl->list_keep); 
     188    for (i = 0; i < size; i++, le = g_list_next (le)) 
     189    { 
     190        WLEntry *e = LENTRY (le->data); 
     191        gboolean match = TRUE; 
     192 
     193        /* Test the query against the list entry. */ 
     194        for (gchar ** p = query_terms; *p != NULL; p++) 
     195        { 
     196            if (**p != '\0' && !strcasestr (e->text, *p)) 
     197            { 
     198                match = FALSE; 
     199                break; 
     200            } 
     201        } 
     202 
     203        /* If all the terms matched, then add the element to the list. */ 
     204        if (match) 
     205            g_queue_push_tail (l->list, filt_listbox_shallow_copy_entry (e, FALSE)); 
     206    } 
     207    if (listbox_is_empty (l)) 
     208    { 
     209        listbox_add_item (l, LISTBOX_APPEND_AT_END, 0, "<no search results>", NULL, FALSE); 
     210        LENTRY (g_queue_peek_head_link (l->list)->data)->index = -2; 
     211    } 
     212    size = g_queue_get_length (l->list); 
     213    if (l->pos >= size) 
     214        listbox_select_entry (l, size - 1); 
     215    else 
     216        listbox_select_entry (l, l->pos); 
     217 
     218    g_strfreev (query_terms); 
     219} 
     220 
     221/* --------------------------------------------------------------------------------------------- */ 
     222 
     223/* Restores original elements of the list (from sl->list_keep) and turns off the WST_FILTER state. */ 
     224static gboolean 
     225filt_listbox_set_to_normal_state (WFilteringListbox * sl) 
     226{ 
     227    WListbox *l = LISTBOX (sl); 
     228    /* The listbox is already in non-filter state? */ 
     229    if (!widget_get_state (WIDGET (l), WST_FILTER)) 
     230    { 
     231        /* Return doing no change, just signal the error. */ 
     232        return FALSE; 
     233    } 
     234 
     235    /* The keep-list must be allocated (even if it's empty). */ 
     236    g_assert (sl->list_keep != NULL); 
     237 
     238    /* Mark the new state. */ 
     239    widget_set_state (WIDGET (l), WST_FILTER, FALSE); 
     240 
     241    /* Release the filtered list and replace it with the original, complete list (it owns the 
     242     * internal data, hence the release is a shallow one). */ 
     243    g_queue_free_full (l->list, g_free); 
     244    l->list = sl->list_keep; 
     245    sl->list_keep = NULL; 
     246    return TRUE; 
     247} 
     248 
     249/* --------------------------------------------------------------------------------------------- */ 
     250 
     251/* 
     252 * Sets the listbox into ·filter· state. In this state, there's a separate copy of all list 
     253 * entries, while the original (and displayed) field ->list is being a filtered version of the 
     254 * full copy. 
     255 */ 
     256static gboolean 
     257filt_listbox_set_to_filter_state (WFilteringListbox * sl) 
     258{ 
     259    WListbox *l = LISTBOX (sl); 
     260    GList *le; 
     261 
     262    /* The listbox is already in filter state? */ 
     263    if (widget_get_state (WIDGET (l), WST_FILTER)) 
     264    { 
     265        /* Return doing no change, just signal the error. */ 
     266        return FALSE; 
     267    } 
     268 
     269    /* Mark the new state. */ 
     270    widget_set_state (WIDGET (l), WST_FILTER, TRUE); 
     271 
     272    /* No list copy when entering filter mode. */ 
     273    g_assert (sl->list_keep == NULL); 
     274    sl->list_keep = g_queue_new (); 
     275 
     276    /* Skip empty lists. */ 
     277    if (listbox_is_empty (l)) 
     278        return TRUE; 
     279 
     280    /* 
     281     * Remember the original position in the list in the field. It'll be used to determine the 
     282     * virtual_pos field. 
     283     */ 
     284    listbox_init_indices (l); 
     285 
     286    /* Perform a shallow copy of the original list. */ 
     287    for (le = g_queue_peek_head_link (l->list); le != NULL; le = g_list_next (le)) 
     288    { 
     289        WLEntry *copy; 
     290        copy = filt_listbox_shallow_copy_entry (LENTRY (le->data), TRUE); 
     291        g_queue_push_tail (sl->list_keep, copy); 
     292    } 
     293 
     294    return TRUE; 
     295} 
     296 
     297/* --------------------------------------------------------------------------------------------- */ 
     298 
     299/* 
     300 * If the list is filtered it replaces from the back list (list_keep). It returns whether such  
     301 * change occurred – FALSE means that the list was already unfiltered. 
     302 */ 
     303gboolean 
     304filt_listbox_ensure_unfiltered_state (WFilteringListbox * sl) 
     305{ 
     306    gboolean ret = FALSE; 
     307    if (filt_listbox_is_filter_state (sl)) 
     308        ret = filt_listbox_set_to_normal_state (sl); 
     309    return ret; 
     310} 
     311 
     312/* --------------------------------------------------------------------------------------------- */ 
     313 
     314gboolean 
     315filt_listbox_conditionally_enable_multi_search_init (WFilteringListbox * sl) 
     316{ 
     317    int start_with_multi_search_active; 
     318 
     319    /* Option of starting the listbox with MultiSearch pre-activated. */ 
     320    start_with_multi_search_active = 
     321        mc_config_get_bool (mc_global.main_config, CONFIG_APP_SECTION, 
     322                            "multi_search_active_by_default", 1); 
     323 
     324    /* CK_MultiSearch toggles the state. */ 
     325    if (start_with_multi_search_active) 
     326        send_message (WIDGET (sl), NULL, MSG_ACTION, CK_MultiSearch, NULL); 
     327    else 
     328        /* Only init embedded position indices. */ 
     329        listbox_init_indices (LISTBOX (sl)); 
     330 
     331    return start_with_multi_search_active; 
     332} 
     333 
     334/* --------------------------------------------------------------------------------------------- */ 
     335/*** public functions ****************************************************************************/ 
     336/* --------------------------------------------------------------------------------------------- */ 
     337 
     338WFilteringListbox * 
     339filtering_listbox_new (int y, int x, int height, int width, 
     340                       gboolean deletable, lcback_fn callback, 
     341                       filt_listbox_resize_strategy_t resize) 
     342{ 
     343    WListbox *base; 
     344    WFilteringListbox *object; 
     345    Widget *w; 
     346 
     347    /* Allocate memory for the object body. */ 
     348    object = g_new (WFilteringListbox, 1); 
     349 
     350    /* Forward the call to construct the inherited object. */ 
     351    base = listbox_new (y, x, height, width, deletable, callback); 
     352 
     353    /* Shallow copy and shallow release. */ 
     354    object->base = *base; 
     355    g_free (base); 
     356 
     357    /* Alter fields of base class. */ 
     358    w = WIDGET (object); 
     359    object->base_callback = w->callback;        /* Save original callback function */ 
     360    w->callback = filt_listbox_callback;        /* Set custom callback handler */ 
     361 
     362    /* Set extending fields of this class. */ 
     363    object->list_keep = NULL;   /* No back buffer at startup */ 
     364    object->resize_strategy = resize;   /* Save resize strategy */ 
     365    object->initialized = FALSE; 
     366 
     367    return object; 
     368} 
     369 
     370/* --------------------------------------------------------------------------------------------- */ 
     371 
     372cb_ret_t 
     373filt_listbox_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 
     374{ 
     375    WFilteringListbox *sl = FILT_LISTBOX (w);   /* s* – from `screen`, a "screened" listbox */ 
     376    cb_ret_t ret = MSG_NOT_HANDLED; 
     377    long activity; 
     378 
     379    switch (msg) 
     380    { 
     381    case MSG_INIT: 
     382        if (!sl->initialized) 
     383        { 
     384            filt_listbox_conditionally_enable_multi_search_init (sl); 
     385            sl->initialized = TRUE; 
     386        } 
     387        /* WListbox doesn't have MSG_INIT, so don't forward. */ 
     388        ret = MSG_HANDLED; 
     389        break; 
     390    case MSG_ACTION: 
     391        if (parm == CK_MultiSearch) 
     392        { 
     393            gboolean retval; 
     394            /* Toggle the multi term searching of any listbox. */ 
     395            if (filt_listbox_is_filter_state (sl)) 
     396            { 
     397                /* Remove the input widget from the dialog. */ 
     398                filt_listbox_hide_multi_search_widget (sl); 
     399                /* Restore original (unfiltered) listbox contents. */ 
     400                retval = filt_listbox_set_to_normal_state (sl); 
     401            } 
     402            else 
     403            { 
     404                /* Add input widget for the filter query at the bottom of the dialog window. */ 
     405                filt_listbox_show_multi_search_widget (sl); 
     406                /* … and then turn on the filter state. */ 
     407                retval = filt_listbox_set_to_filter_state (sl); 
     408            } 
     409            if (!retval) 
     410                message (D_ERROR | D_CENTER, MSG_ERROR, 
     411                         "An internal error #3 occurred (filtered listbox support)."); 
     412 
     413            ret = MSG_HANDLED; 
     414        } 
     415        break; 
     416 
     417    case MSG_KEY: 
     418        activity = widget_lookup_key (WIDGET (sl), parm); 
     419        if (activity == CK_MultiSearch) 
     420            ret = send_message (w, NULL, MSG_ACTION, CK_MultiSearch, NULL); 
     421        break; 
     422 
     423    case MSG_UPDATE_LIST: 
     424        if (widget_get_state (w, WST_FILTER)) 
     425        { 
     426            filt_listbox_filter_list (sl, (char *) data); 
     427            ret = MSG_HANDLED; 
     428        } 
     429        widget_draw (w); 
     430        widget_draw (sender); 
     431        break; 
     432 
     433    case MSG_DESTROY: 
     434        filt_listbox_ensure_unfiltered_state (sl); 
     435        /* ret is unhandled → the message will be forwarded to base class. */ 
     436        break; 
     437    default: 
     438        break; 
     439    } 
     440 
     441    /* Forward action to base class in case it's not yet handled. */ 
     442    if (ret == MSG_NOT_HANDLED) 
     443        ret = sl->base_callback (w, sender, msg, parm, data); 
     444 
     445    return ret; 
     446} 
     447 
     448/* --------------------------------------------------------------------------------------------- */ 
  • new file lib/widget/filtering_listbox.h

    diff --git a/lib/widget/filtering_listbox.h b/lib/widget/filtering_listbox.h
    new file mode 100644
    index 000000000..f51f1ec56
    - +  
     1#ifndef MC__FILTERING_LISTBOX_H 
     2#define MC__FILTERING_LISTBOX_H 
     3 
     4#include <glib-2.0/glib.h>      /* GQueue */ 
     5 
     6/*** typedefs(not structures) and defined constants **********************************************/ 
     7 
     8/* Casting macros. */ 
     9#define FILT_LISTBOX(x) ((WFilteringListbox *)(x)) 
     10#define CONST_FILT_LISTBOX(x) ((const WFilteringListbox *)(x)) 
     11 
     12/*** enums ***************************************************************************************/ 
     13 
     14typedef enum filt_listbox_resize_strategy_e 
     15{ 
     16    FILT_LIST_EXTEND_DIALOG = 0, 
     17    FILT_LIST_KEEP_DIALOG_SIZE, 
     18    FILT_LIST_DIALOG_AUTO_RESIZE 
     19} filt_listbox_resize_strategy_t; 
     20 
     21/*** structures declarations (and typedefs of structures)*****************************************/ 
     22 
     23typedef struct WFilteringListbox_s 
     24{ 
     25    WListbox base; 
     26    widget_cb_fn base_callback; /* Saved callback of base class */ 
     27    gboolean initialized;       /* Whether MSG_INIT has been received. */ 
     28 
     29    /* Fields for new logic. */ 
     30    GQueue *list_keep;          /* Unfiltered list (used in  WST_FILTER state). */ 
     31    filt_listbox_resize_strategy_t resize_strategy; 
     32} WFilteringListbox; 
     33 
     34/*** global variables defined in .c file *********************************************************/ 
     35 
     36/*** declarations of public functions ************************************************************/ 
     37 
     38WFilteringListbox *filtering_listbox_new (int y, int x, int height, int width, 
     39                                          gboolean deletable, lcback_fn callback, 
     40                                          filt_listbox_resize_strategy_t resize); 
     41gboolean filt_listbox_ensure_unfiltered_state (WFilteringListbox * l); 
     42gboolean filt_listbox_conditionally_enable_multi_search_init (WFilteringListbox * l); 
     43void filt_listbox_select_entry (WFilteringListbox * sl, int dest); 
     44cb_ret_t filt_listbox_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, 
     45                                void *data); 
     46 
     47/*** inline functions ****************************************************************************/ 
     48 
     49#endif /* MC__FILTERING_LISTBOX_H */ 
  • new file lib/widget/forwarding_input.c

    diff --git a/lib/widget/forwarding_input.c b/lib/widget/forwarding_input.c
    new file mode 100644
    index 000000000..1b0157f88
    - +  
     1/* 
     2   A key forwarding extended input class. 
     3 
     4   Copyright (C) 2021 
     5   Free Software Foundation, Inc. 
     6 
     7   Written by: 
     8   Sebastian Gniazdowski <sgniazdowski@gmail.com>, 2021. 
     9 
     10   This file is part of the Midnight Commander. 
     11 
     12   The Midnight Commander is free software: you can redistribute it 
     13   and/or modify it under the terms of the GNU General Public License as 
     14   published by the Free Software Foundation, either version 3 of the License, 
     15   or (at your option) any later version. 
     16 
     17   The Midnight Commander is distributed in the hope that it will be useful, 
     18   but WITHOUT ANY WARRANTY; without even the implied warranty of 
     19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     20   GNU General Public License for more details. 
     21 
     22   You should have received a copy of the GNU General Public License 
     23   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     24 */ 
     25 
     26/** \file forwarding-input.c 
     27 *  \brief This input class has a feature of forwarding unrecognized keys to a widget passed at  
     28 *         creation. 
     29 *  \author Sebastian Gniazdowski 
     30 *  \date 2021 
     31 * 
     32 *  It's being used by MultiSearch to allow moving across listbox while typing to the input. 
     33 */ 
     34 
     35#include <config.h> 
     36 
     37#include "lib/global.h" 
     38#include "lib/widget.h" 
     39 
     40/*** global variables ****************************************************************************/ 
     41 
     42/*** file scope macro definitions ****************************************************************/ 
     43 
     44/*** file scope type declarations ****************************************************************/ 
     45 
     46/*** file scope variables ************************************************************************/ 
     47 
     48/*** file scope functions ************************************************************************/ 
     49/* --------------------------------------------------------------------------------------------- */ 
     50 
     51/* --------------------------------------------------------------------------------------------- */ 
     52/*** public functions ****************************************************************************/ 
     53/* --------------------------------------------------------------------------------------------- */ 
     54 
     55WForwardingInput * 
     56forwarding_input_new (int y, int x, const int *colors, 
     57                      int len, const char *text, const char *histname, 
     58                      input_complete_t completion_flags, Widget * forward_to_widget) 
     59{ 
     60    WInput *base; 
     61    WForwardingInput *object; 
     62    Widget *w; 
     63 
     64    /* Allocate memory for the object body. */ 
     65    object = g_new (WForwardingInput, 1); 
     66 
     67    /* Forward the call to construct the inherited object. */ 
     68    base = input_new (y, x, colors, len, text, histname, completion_flags); 
     69 
     70    /* Shallow copy and shallow release. */ 
     71    object->base = *base; 
     72    g_free (base); 
     73 
     74    /* Alter fields of base class. */ 
     75    w = WIDGET (object); 
     76    object->base_callback = w->callback;        /* Save original callback function */ 
     77    w->callback = forw_input_callback;  /* Set custom callback handler */ 
     78 
     79    /* Set  extending fields of this class. */ 
     80    object->forward_to_widget = forward_to_widget; 
     81    return object; 
     82} 
     83 
     84/* --------------------------------------------------------------------------------------------- */ 
     85 
     86cb_ret_t 
     87forw_input_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 
     88{ 
     89    WForwardingInput *in = FORW_INPUT (w); 
     90    gboolean key_message = FALSE; 
     91    cb_ret_t ret; 
     92 
     93    switch (msg) 
     94    { 
     95    case MSG_KEY: 
     96        ret = forw_input_handle_char (in, parm); 
     97        key_message = TRUE; 
     98        break; 
     99    default: 
     100        break; 
     101    } 
     102 
     103    /* 
     104     * Simply pass on all messages to the base class (except for MSG_KEY, which might have 
     105     * been possibly already sent from forw_input_handle_char() function). 
     106     */ 
     107 
     108    if (!key_message) 
     109        ret = in->base_callback (WIDGET (in), sender, msg, parm, data); 
     110 
     111    return ret; 
     112} 
     113 
     114/* --------------------------------------------------------------------------------------------- */ 
     115 
     116cb_ret_t 
     117forw_input_handle_char (WForwardingInput * in, int key) 
     118{ 
     119    cb_ret_t ret = MSG_NOT_HANDLED; 
     120    gboolean sent_to_base = FALSE; 
     121    long activity; 
     122    char *str_cp; 
     123 
     124    /* Save to detect if a change happened. */ 
     125    str_cp = g_strdup (in->base.buffer); 
     126 
     127    /* Is this key recognized by the base object? */ 
     128    activity = widget_lookup_key (WIDGET (in), key); 
     129    if (activity != CK_IgnoreKey && activity != CK_Complete) 
     130    { 
     131        /* Yes → send the key to the upper class. */ 
     132        ret = in->base_callback (WIDGET (in), WIDGET (in), MSG_KEY, key, NULL); 
     133        sent_to_base = TRUE; 
     134    } 
     135    /* Should we try to forward the key to any paired widget? */ 
     136    if (in->forward_to_widget && ret == MSG_NOT_HANDLED) 
     137    { 
     138        /* Is it maybe recognized by forward_to_widget paired object? */ 
     139        activity = widget_lookup_key (WIDGET (in->forward_to_widget), key); 
     140        if (activity != CK_IgnoreKey) 
     141        { 
     142            /* Yes → forward the key to the paired widget (most probably WListbox). */ 
     143            ret = send_message (WIDGET (in->forward_to_widget), NULL, MSG_KEY, key, NULL); 
     144        } 
     145    } 
     146 
     147    /* 
     148     * If not handled yet, then send the key to the base object for general recognition (if 
     149     * not already done that). 
     150     */ 
     151 
     152    if (!sent_to_base && ret == MSG_NOT_HANDLED) 
     153    { 
     154        ret = in->base_callback (WIDGET (in), WIDGET (in), MSG_KEY, key, NULL); 
     155        sent_to_base = TRUE;    /* unused */ 
     156    } 
     157 
     158    /* Send update signal to paired widget ·if· input's text has changed. */ 
     159    if (in->forward_to_widget != NULL && g_strcmp0 (str_cp, in->base.buffer) != 0) 
     160        send_message (WIDGET (in->forward_to_widget), NULL, MSG_UPDATE_LIST, key, in->base.buffer); 
     161    g_free (str_cp); 
     162 
     163    return ret; 
     164} 
     165 
     166/* --------------------------------------------------------------------------------------------- */ 
  • new file lib/widget/forwarding_input.h

    diff --git a/lib/widget/forwarding_input.h b/lib/widget/forwarding_input.h
    new file mode 100644
    index 000000000..5b4e5961a
    - +  
     1#ifndef MC__FORWARDING_INPUT_H 
     2#define MC__FORWARDING_INPUT_H 
     3 
     4/*** typedefs(not structures) and defined constants **********************************************/ 
     5 
     6/* Casting macros. */ 
     7#define FORW_INPUT(x) ((WForwardingInput *)(x)) 
     8#define CONST_FORW_INPUT(x) ((const WForwardingInput *)(x)) 
     9 
     10typedef struct 
     11{ 
     12    WInput base; 
     13    widget_cb_fn base_callback; /* Saved callback of  base class */ 
     14 
     15    /* Fields for new logic. */ 
     16    Widget *forward_to_widget;  /* The paired widget to receive unhandled keys */ 
     17} WForwardingInput; 
     18 
     19/*** enums ***************************************************************************************/ 
     20 
     21/*** structures declarations (and typedefs of structures)*****************************************/ 
     22 
     23/*** global variables defined in .c file *********************************************************/ 
     24 
     25/*** declarations of public functions ************************************************************/ 
     26 
     27WForwardingInput *forwarding_input_new (int y, int x, const int *colors, 
     28                                        int len, const char *text, const char *histname, 
     29                                        input_complete_t completion_flags, 
     30                                        Widget * forward_to_widget); 
     31 
     32cb_ret_t forw_input_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data); 
     33cb_ret_t forw_input_handle_char (WForwardingInput * in, int key); 
     34 
     35/*** inline functions ****************************************************************************/ 
     36 
     37#endif /* MC__FORWARDING_INPUT_H */ 
  • lib/widget/group.c

    diff --git a/lib/widget/group.c b/lib/widget/group.c
    index f8e318bd9..f16de833f 100644
    a b group_add_widget_autopos (WGroup * g, void *w, widget_pos_flags_t pos_flags, con 
    749749 * @param w Widget object 
    750750 */ 
    751751void 
    752 group_remove_widget (void *w) 
     752group_remove_widget (void *wid) 
    753753{ 
     754    Widget *w = WIDGET (wid); 
    754755    WGroup *g; 
    755756    GList *d; 
    756757 
    757758    /* Don't accept NULL widget. This shouldn't happen */ 
    758759    assert (w != NULL); 
    759760 
    760     g = WIDGET (w)->owner; 
     761    /* Invoke widget's pre unlink callback. */ 
     762    if (w->pre_unlink_func != NULL) 
     763        w->pre_unlink_func (w); 
     764 
     765    g = w->owner; 
    761766 
    762767    d = g_list_find (g->widgets, w); 
    763768    if (d == g->current) 
    group_remove_widget (void *w) 
    774779        group_select_current_widget (g); 
    775780    } 
    776781 
    777     WIDGET (w)->owner = NULL; 
     782    w->owner = NULL; 
    778783} 
    779784 
    780785/* --------------------------------------------------------------------------------------------- */ 
  • lib/widget/history.c

    diff --git a/lib/widget/history.c b/lib/widget/history.c
    index 775d02b1b..2ee719ca7 100644
    a b typedef struct 
    6666/*** file scope functions ************************************************************************/ 
    6767 
    6868static cb_ret_t 
    69 history_dlg_reposition (WDialog * dlg_head) 
     69history_dlg_reposition (WDialog * dlg_head, WRect * resize) 
    7070{ 
    71     history_dlg_data *data; 
    72     int x = 0, y, he, wi; 
    7371    WRect r; 
    7472 
    75     /* guard checks */ 
    76     if ((dlg_head == NULL) || (dlg_head->data == NULL)) 
    77         return MSG_NOT_HANDLED; 
    78  
    79     data = (history_dlg_data *) dlg_head->data; 
    80  
    81     y = data->y; 
    82     he = data->count + 2; 
    83  
    84     if (he <= y || y > (LINES - 6)) 
     73    if (resize == NULL) 
    8574    { 
    86         he = MIN (he, y - 1); 
    87         y -= he; 
     75        history_dlg_data *data; 
     76        int x = 0, y, he, wi; 
     77 
     78        /* guard checks */ 
     79        if ((dlg_head == NULL) || (dlg_head->data == NULL)) 
     80            return MSG_NOT_HANDLED; 
     81 
     82        data = (history_dlg_data *) dlg_head->data; 
     83 
     84        y = data->y; 
     85        he = data->count + 2; 
     86 
     87        if (he <= y || y > (LINES - 6)) 
     88        { 
     89            he = MIN (he, y - 1); 
     90            y -= he; 
     91        } 
     92        else 
     93        { 
     94            y++; 
     95            he = MIN (he, LINES - y); 
     96        } 
     97 
     98        if (data->x > 2) 
     99            x = data->x - 2; 
     100 
     101        wi = data->max_width + 4; 
     102 
     103        if ((wi + x) > COLS) 
     104        { 
     105            wi = MIN (wi, COLS); 
     106            x = COLS - wi; 
     107        } 
     108        rect_init (&r, y, x, he, wi); 
    88109    } 
    89110    else 
    90111    { 
    91         y++; 
    92         he = MIN (he, LINES - y); 
     112        /* A resize from some other code (currently from the listbox filter). */ 
     113        r = *resize; 
    93114    } 
    94115 
    95     if (data->x > 2) 
    96         x = data->x - 2; 
    97  
    98     wi = data->max_width + 4; 
    99  
    100     if ((wi + x) > COLS) 
    101     { 
    102         wi = MIN (wi, COLS); 
    103         x = COLS - wi; 
    104     } 
    105  
    106     rect_init (&r, y, x, he, wi); 
    107116 
    108117    return dlg_default_callback (WIDGET (dlg_head), NULL, MSG_RESIZE, 0, &r); 
    109118} 
    history_dlg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, v 
    116125    switch (msg) 
    117126    { 
    118127    case MSG_RESIZE: 
    119         return history_dlg_reposition (DIALOG (w)); 
     128        return history_dlg_reposition (DIALOG (w), data); 
    120129 
    121130    case MSG_NOTIFY: 
    122131        { 
    history_create_item (history_descriptor_t * hd, void *data) 
    158167    width = str_term_width1 (text); 
    159168    hd->max_width = MAX (width, hd->max_width); 
    160169 
    161     listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE); 
     170    listbox_add_item (LISTBOX (hd->listbox), LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE); 
    162171} 
    163172 
    164173/* --------------------------------------------------------------------------------------------- */ 
    history_descriptor_init (history_descriptor_t * hd, int y, int x, GList * histor 
    190199    hd->action = CK_IgnoreKey; 
    191200    hd->text = NULL; 
    192201    hd->max_width = 0; 
    193     hd->listbox = listbox_new (1, 1, 2, 2, TRUE, NULL); 
     202    hd->listbox = filtering_listbox_new (1, 1, 2, 2, TRUE, NULL, FILT_LIST_KEEP_DIALOG_SIZE); 
    194203    /* in most cases history list contains string only and no any other data */ 
    195204    hd->create = history_create_item; 
    196205    hd->release = history_release_item; 
    history_show (history_descriptor_t * hd) 
    205214    GList *z, *hi; 
    206215    size_t count; 
    207216    WDialog *query_dlg; 
     217    WListbox *lw; 
    208218    history_dlg_data hist_data; 
    209219    int dlg_ret; 
    210220 
    history_show (history_descriptor_t * hd) 
    217227        hd->create (hd, z->data); 
    218228    /* after this, the order of history items is following: recent at begin, oldest at end */ 
    219229 
    220     count = listbox_get_length (hd->listbox); 
     230    /* Get the WListbox pointer for convenience. */ 
     231    lw = LISTBOX (hd->listbox); 
     232    count = listbox_get_length (lw); 
    221233 
    222234    hist_data.y = hd->y; 
    223235    hist_data.x = hd->x; 
    history_show (history_descriptor_t * hd) 
    244256    { 
    245257        /* history is above base widget -- revert order to place recent item at bottom */ 
    246258        /* revert history direction */ 
    247         g_queue_reverse (hd->listbox->list); 
     259        g_queue_reverse (lw->list); 
    248260        if (hd->current < 0 || (size_t) hd->current >= count) 
    249             listbox_select_last (hd->listbox); 
     261            listbox_select_last (lw); 
    250262        else 
    251             listbox_select_entry (hd->listbox, count - 1 - (size_t) hd->current); 
     263            listbox_select_entry (lw, count - 1 - (size_t) hd->current); 
    252264    } 
    253265    else 
    254266    { 
    255267        /* history is below base widget -- keep order to place recent item on top  */ 
    256268        if (hd->current > 0) 
    257             listbox_select_entry (hd->listbox, hd->current); 
     269            listbox_select_entry (lw, hd->current); 
    258270    } 
    259271 
    260272    dlg_ret = dlg_run (query_dlg); 
    history_show (history_descriptor_t * hd) 
    274286            hd->action = CK_Enter; 
    275287        } 
    276288 
    277         listbox_get_current (hd->listbox, &q, NULL); 
    278         hd->text = g_strdup (q); 
     289        listbox_get_current (lw, &q, NULL); 
     290        /* Can still be 0 if special entry "<no search results>" will be selected. */ 
     291        if (q != NULL) 
     292            hd->text = g_strdup (q); 
    279293    } 
    280294 
     295    /* If needed, restore normal listbox state, with no backlist (list_keep). */ 
     296    filt_listbox_ensure_unfiltered_state (hd->listbox); 
     297 
    281298    /* get modified history from dialog */ 
    282299    z = NULL; 
    283     for (hi = listbox_get_first_link (hd->listbox); hi != NULL; hi = g_list_next (hi)) 
     300    for (hi = listbox_get_first_link (lw); hi != NULL; hi = g_list_next (hi)) 
    284301        /* history is being reverted here again */ 
    285302        z = g_list_prepend (z, hd->release (hd, LENTRY (hi->data))); 
    286303 
  • lib/widget/history.h

    diff --git a/lib/widget/history.h b/lib/widget/history.h
    index 9c4b403d1..23f4d403d 100644
    a b  
    1111/* forward declarations */ 
    1212struct history_descriptor_t; 
    1313struct WLEntry; 
    14 struct WListbox; 
     14typedef struct WFilteringListbox_s WFilteringListbox; 
    1515 
    1616typedef void (*history_create_item_func) (struct history_descriptor_t * hd, void *data); 
    1717typedef void *(*history_release_item_func) (struct history_descriptor_t * hd, struct WLEntry * le); 
    typedef struct history_descriptor_t 
    3030    char *text;                 /**< return text of selected item */ 
    3131 
    3232    size_t max_width;           /**< maximum width of sring in history */ 
    33     struct WListbox *listbox;   /**< listbox widget to draw history */ 
     33    WFilteringListbox *listbox;   /**< listbox widget to draw history */ 
    3434 
    3535    history_create_item_func create;    /**< function to create item of @list */ 
    3636    history_release_item_func release;  /**< function to release item of @list */ 
  • lib/widget/input.c

    diff --git a/lib/widget/input.c b/lib/widget/input.c
    index 471715c25..653e870cd 100644
    a b input_save_history (const gchar * event_group_name, const gchar * event_name, 
    871871    (void) event_group_name; 
    872872    (void) event_name; 
    873873 
    874     if (!in->is_password && (DIALOG (WIDGET (in)->owner)->ret_value != B_CANCEL)) 
     874    if (!in->is_password && WIDGET (in)->owner 
     875        && (DIALOG (WIDGET (in)->owner)->ret_value != B_CANCEL)) 
    875876    { 
    876877        ev_history_load_save_t *ev = (ev_history_load_save_t *) data; 
    877878 
    input_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 
    970971    } 
    971972} 
    972973 
     974/* --------------------------------------------------------------------------------------------- */ 
     975 
     976static void 
     977listbox_unregister_history_events_cb (gpointer wid_ptr) 
     978{ 
     979    Widget *w = WIDGET (wid_ptr); 
     980    WDialog *h = DIALOG (w->owner); 
     981 
     982    /* unsubscribe from "history_load" event */ 
     983    mc_event_del (h->event_group, MCEVENT_HISTORY_LOAD, input_load_history, w); 
     984    /* unsubscribe from "history_save" event */ 
     985    mc_event_del (h->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w); 
     986} 
     987 
    973988/* --------------------------------------------------------------------------------------------- */ 
    974989/*** public functions ****************************************************************************/ 
    975990/* --------------------------------------------------------------------------------------------- */ 
    input_new (int y, int x, const int *colors, int width, const char *def_text, 
    10281043    if ((histname != NULL) && (*histname != '\0')) 
    10291044        in->history.name = g_strdup (histname); 
    10301045    /* history will be loaded later */ 
    1031  
    10321046    in->label = NULL; 
    10331047 
    10341048    return in; 
    input_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *d 
    10501064        mc_event_add (h->event_group, MCEVENT_HISTORY_LOAD, input_load_history, w, NULL); 
    10511065        /* subscribe to "history_save" event */ 
    10521066        mc_event_add (h->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w, NULL); 
     1067        /* unregister (via the func) the events in case of removal from dialog */ 
     1068        w->pre_unlink_func = listbox_unregister_history_events_cb; 
    10531069        if (in->label != NULL) 
    10541070            widget_set_state (WIDGET (in->label), WST_DISABLED, widget_get_state (w, WST_DISABLED)); 
    10551071        return MSG_HANDLED; 
    input_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *d 
    10631079            return v; 
    10641080        } 
    10651081 
    1066         /* Keys we want others to handle */ 
     1082        /* Keys we want others to handle. */ 
    10671083        if (parm == KEY_UP || parm == KEY_DOWN || parm == ESC_CHAR 
    10681084            || parm == KEY_F (10) || parm == '\n') 
    10691085            return MSG_NOT_HANDLED; 
    input_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *d 
    10971113        return MSG_HANDLED; 
    10981114 
    10991115    case MSG_DESTROY: 
    1100         /* unsubscribe from "history_load" event */ 
    1101         mc_event_del (h->event_group, MCEVENT_HISTORY_LOAD, input_load_history, w); 
    1102         /* unsubscribe from "history_save" event */ 
    1103         mc_event_del (h->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w); 
     1116        /* …only, if there is an owner WGroup. */ 
     1117        if (h != NULL) 
     1118        { 
     1119            /* unsubscribe from "history_load" event */ 
     1120            mc_event_del (h->event_group, MCEVENT_HISTORY_LOAD, input_load_history, w); 
     1121            /* unsubscribe from "history_save" event */ 
     1122            mc_event_del (h->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w); 
     1123        } 
    11041124        input_destroy (in); 
    11051125        return MSG_HANDLED; 
    11061126 
  • lib/widget/input_complete.c

    diff --git a/lib/widget/input_complete.c b/lib/widget/input_complete.c
    index c23fe6063..7bee2ff11 100644
    a b complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    10171017{ 
    10181018    static int bl = 0; 
    10191019 
    1020     WGroup *g = GROUP (w); 
    10211020    WDialog *h = DIALOG (w); 
     1021    WFilteringListbox *slw; 
     1022    cb_ret_t ret = MSG_NOT_HANDLED; 
     1023 
     1024    /* Find the listbox in dialog's group. */ 
     1025    slw = FILT_LISTBOX (WIDGET (h)->find_by_type (WIDGET (h), filt_listbox_callback)); 
    10221026 
    10231027    switch (msg) 
    10241028    { 
    complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    10271031        { 
    10281032        case KEY_LEFT: 
    10291033        case KEY_RIGHT: 
     1034            /* MultiSearch (list filtering) is allowing for left/right movement in query input. */ 
     1035            if (widget_get_state (WIDGET (slw), WST_FILTER)) 
     1036                break; 
    10301037            bl = 0; 
    10311038            h->ret_value = 0; 
    10321039            dlg_stop (h); 
    1033             return MSG_HANDLED; 
     1040            ret = MSG_HANDLED; 
     1041            break; 
    10341042 
    10351043        case KEY_BACKSPACE: 
     1044            /* MultiSearch is exclusive with completion widening. */ 
     1045            if (widget_get_state (WIDGET (slw), WST_FILTER)) 
     1046                break; 
    10361047            bl = 0; 
    10371048            /* exit from completion list if input line is empty */ 
    10381049            if (end == 0) 
    complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    10561067 
    10571068                new_end = str_get_prev_char (&input->buffer[end]) - input->buffer; 
    10581069 
    1059                 for (i = 0, e = listbox_get_first_link (LISTBOX (g->current->data)); 
     1070                for (i = 0, e = listbox_get_first_link (LISTBOX (slw)); 
    10601071                     e != NULL; i++, e = g_list_next (e)) 
    10611072                { 
    10621073                    WLEntry *le = LENTRY (e->data); 
    10631074 
    10641075                    if (strncmp (input->buffer + start, le->text, new_end - start) == 0) 
    10651076                    { 
    1066                         listbox_select_entry (LISTBOX (g->current->data), i); 
     1077                        listbox_select_entry (LISTBOX (slw), i); 
    10671078                        end = new_end; 
    10681079                        input_handle_char (input, parm); 
    1069                         widget_draw (WIDGET (g->current->data)); 
     1080                        widget_draw (WIDGET (slw)); 
    10701081                        break; 
    10711082                    } 
    10721083                } 
    10731084            } 
    1074             return MSG_HANDLED; 
     1085            ret = MSG_HANDLED; 
     1086            break; 
    10751087 
    10761088        default: 
    10771089            if (parm < 32 || parm > 255) 
    10781090            { 
    10791091                bl = 0; 
    1080                 if (widget_lookup_key (WIDGET (input), parm) != CK_Complete) 
    1081                     return MSG_NOT_HANDLED; 
    1082  
    1083                 if (end == min_end) 
    1084                     return MSG_HANDLED; 
    1085  
    1086                 /* This means we want to refill the list box and start again */ 
    1087                 h->ret_value = B_USER; 
    1088                 dlg_stop (h); 
     1092                /* CK_Complete → Is completion up to date? */ 
     1093                if ((widget_lookup_key (WIDGET (input), parm) == CK_Complete) && (end != min_end)) 
     1094                { 
     1095                    /* This means we want to refill the list box and start again. */ 
     1096                    h->ret_value = B_USER; 
     1097                    dlg_stop (h); 
     1098                } 
     1099                /* 
     1100                 * else – key will be ignored by this function, so leave ret unchanged – allow other 
     1101                 * widgets to process it. 
     1102                 */ 
    10891103            } 
    1090             else 
     1104            /* 
     1105             * Do standard live entry lookup only when not filtering list via MultiSearch – it is 
     1106             * a feature that to a great extent replaces old engine. It can be still used as MultiSearch  
     1107             * can be dynamically enabled and disabled (default by alt-space and ctrl-space). 
     1108             */ 
     1109            else if (!widget_get_state (WIDGET (slw), WST_FILTER)) 
    10911110            { 
    10921111                static char buff[MB_LEN_MAX] = ""; 
    10931112                GList *e; 
    complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    11101129                    break; 
    11111130                } 
    11121131 
    1113                 for (i = 0, e = listbox_get_first_link (LISTBOX (g->current->data)); 
     1132                for (i = 0, e = listbox_get_first_link (LISTBOX (slw)); 
    11141133                     e != NULL; i++, e = g_list_next (e)) 
    11151134                { 
    11161135                    WLEntry *le = LENTRY (e->data); 
    complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    11211140                        if (need_redraw == 0) 
    11221141                        { 
    11231142                            need_redraw = 1; 
    1124                             listbox_select_entry (LISTBOX (g->current->data), i); 
     1143                            listbox_select_entry (LISTBOX (slw), i); 
    11251144                            last_text = le->text; 
    11261145                        } 
    11271146                        else 
    complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    11721191                if (need_redraw == 2) 
    11731192                { 
    11741193                    insert_text (input, last_text, low); 
    1175                     widget_draw (WIDGET (g->current->data)); 
     1194                    widget_draw (WIDGET (slw)); 
    11761195                } 
    11771196                else if (need_redraw == 1) 
    11781197                { 
    complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    11801199                    dlg_stop (h); 
    11811200                } 
    11821201                bl = 0; 
     1202                ret = MSG_HANDLED; 
    11831203            } 
    11841204        } 
    1185         return MSG_HANDLED; 
     1205        break; 
    11861206 
    11871207    default: 
    11881208        return dlg_default_callback (w, sender, msg, parm, data); 
    11891209    } 
     1210    return ret; 
    11901211} 
    11911212 
    11921213/* --------------------------------------------------------------------------------------------- */ 
    complete_engine (WInput * in, int what_to_do) 
    12231244            int start_x, start_y; 
    12241245            char **p, *q; 
    12251246            WDialog *complete_dlg; 
    1226             WListbox *complete_list; 
     1247            WFilteringListbox *complete_list; 
    12271248 
    12281249            for (p = in->completions + 1; *p != NULL; count++, p++) 
    12291250            { 
    complete_engine (WInput * in, int what_to_do) 
    12661287            complete_dlg = 
    12671288                dlg_create (TRUE, y, x, complete_height, complete_width, WPOS_KEEP_DEFAULT, TRUE, 
    12681289                            dialog_colors, complete_callback, NULL, "[Completion]", NULL); 
    1269             complete_list = listbox_new (1, 1, h - 2, w - 2, FALSE, NULL); 
     1290            complete_list = filtering_listbox_new (1, 1, h - 2, w - 2, FALSE, NULL, 
     1291                                                   FILT_LIST_KEEP_DIALOG_SIZE); 
    12701292            group_add_widget (GROUP (complete_dlg), complete_list); 
    12711293 
    12721294            for (p = in->completions + 1; *p != NULL; p++) 
    1273                 listbox_add_item (complete_list, LISTBOX_APPEND_AT_END, 0, *p, NULL, FALSE); 
     1295                listbox_add_item (LISTBOX (complete_list), LISTBOX_APPEND_AT_END, 0, *p, NULL, 
     1296                                  FALSE); 
    12741297 
    12751298            i = dlg_run (complete_dlg); 
    12761299            q = NULL; 
    12771300            if (i == B_ENTER) 
    12781301            { 
    1279                 listbox_get_current (complete_list, &q, NULL); 
     1302                listbox_get_current (LISTBOX (complete_list), &q, NULL); 
    12801303                if (q != NULL) 
    12811304                    insert_text (in, q, strlen (q)); 
    12821305            } 
    12831306            if (q != NULL || end != min_end) 
    12841307                input_complete_free (in); 
     1308 
    12851309            dlg_destroy (complete_dlg); 
    12861310 
    12871311            /* B_USER if user wants to start over again */ 
  • lib/widget/listbox-window.c

    diff --git a/lib/widget/listbox-window.c b/lib/widget/listbox-window.c
    index 44548b485..eb0796a1e 100644
    a b create_listbox_window_centered (int center_y, int center_x, int lines, int cols, 
    108108        dlg_create (TRUE, ypos, xpos, lines + space, cols + space, pos_flags, FALSE, listbox_colors, 
    109109                    NULL, NULL, help, title); 
    110110 
    111     listbox->list = listbox_new (2, 2, lines, cols, FALSE, NULL); 
    112     group_add_widget (GROUP (listbox->dlg), listbox->list); 
     111    listbox->list = 
     112        filtering_listbox_new (2, 2, lines, cols, FALSE, NULL, FILT_LIST_DIALOG_AUTO_RESIZE); 
     113    group_add_widget (GROUP (listbox->dlg), WIDGET (listbox->list)); 
    113114 
    114115    return listbox; 
    115116} 
    create_listbox_window (int lines, int cols, const char *title, const char *help) 
    128129int 
    129130run_listbox (Listbox * l) 
    130131{ 
     132    WListbox *lw = LISTBOX (l->list); 
    131133    int val = -1; 
    132134 
    133135    if (dlg_run (l->dlg) != B_CANCEL) 
    134         val = l->list->pos; 
     136    { 
     137        /* Get the virtual index first, to support filtered listboxes. */ 
     138        val = lw->virtual_pos; 
     139 
     140        /* No virtual position → get pos. */ 
     141        if (val == -1) 
     142            val = lw->pos; 
     143    } 
     144 
    135145    dlg_destroy (l->dlg); 
    136146    g_free (l); 
    137147    return val; 
    run_listbox (Listbox * l) 
    149159void * 
    150160run_listbox_with_data (Listbox * l, const void *select) 
    151161{ 
     162    WListbox *lw = LISTBOX (l->list); 
    152163    void *val = NULL; 
    153164 
    154165    if (select != NULL) 
    155         listbox_select_entry (l->list, listbox_search_data (l->list, select)); 
     166        listbox_select_entry (lw, listbox_search_data (lw, select)); 
    156167 
    157168    if (dlg_run (l->dlg) != B_CANCEL) 
    158169    { 
    159170        WLEntry *e; 
    160         e = listbox_get_nth_item (l->list, l->list->pos); 
    161         if (e != NULL) 
     171        e = listbox_get_nth_item (lw, lw->pos); 
     172        /* -2 means that "<no search results>" has been selected. */ 
     173        if (e != NULL && e->index != -2) 
    162174        { 
    163175            /* The assert guards against returning a soon-to-be deallocated 
    164176             * pointer (as in listbox_add_item(..., TRUE)). */ 
  • lib/widget/listbox-window.h

    diff --git a/lib/widget/listbox-window.h b/lib/widget/listbox-window.h
    index 5a6082956..dc20cee13 100644
    a b  
    88/*** typedefs(not structures) and defined constants **********************************************/ 
    99 
    1010#define LISTBOX_APPEND_TEXT(l,h,t,d,f) \ 
    11     listbox_add_item (l->list, LISTBOX_APPEND_AT_END, h, t, d, f) 
     11    listbox_add_item (LISTBOX(l->list), LISTBOX_APPEND_AT_END, h, t, d, f) 
    1212 
    1313/*** enums ***************************************************************************************/ 
    1414 
     
    1717typedef struct 
    1818{ 
    1919    WDialog *dlg; 
    20     WListbox *list; 
     20    WFilteringListbox *list; 
    2121} Listbox; 
    2222 
    2323/*** global variables defined in .c file *********************************************************/ 
  • lib/widget/listbox.c

    diff --git a/lib/widget/listbox.c b/lib/widget/listbox.c
    index e20c1a82d..942dad7a9 100644
    a b listbox_entry_free (void *data) 
    7777{ 
    7878    WLEntry *e = data; 
    7979 
    80     g_free (e->text); 
     80    if (e->free_text) 
     81        g_free (e->text); 
    8182    if (e->free_data) 
    8283        g_free (e->data); 
    8384    g_free (e); 
    listbox_key (WListbox * l, int key) 
    358359 
    359360/* --------------------------------------------------------------------------------------------- */ 
    360361 
     362/* When called via g_queue_foreach it assigns the index field with an incremented int. */ 
     363static void 
     364listbox_foreach_apply_index (gpointer data, gpointer user_data) 
     365{ 
     366    WLEntry *e = data; 
     367    int *cur_idx = user_data; 
     368 
     369    /* Set the index and increment it. */ 
     370    e->index = *cur_idx; 
     371    *cur_idx = *cur_idx + 1; 
     372} 
     373 
     374/* --------------------------------------------------------------------------------------------- */ 
     375 
    361376/* Listbox item adding function */ 
    362377static inline void 
    363378listbox_append_item (WListbox * l, WLEntry * e, listbox_append_t pos) 
    listbox_new (int y, int x, int height, int width, gboolean deletable, lcback_fn 
    556571    l = g_new (WListbox, 1); 
    557572    w = WIDGET (l); 
    558573    widget_init (w, y, x, height, width, listbox_callback, listbox_mouse_callback); 
    559     w->options |= WOP_SELECTABLE | WOP_WANT_HOTKEY; 
     574    w->options |= WOP_SELECTABLE; 
    560575    w->keymap = listbox_map; 
    561576 
    562577    l->list = NULL; 
    563     l->top = l->pos = 0; 
     578    l->top = l->pos = l->virtual_pos = 0; 
    564579    l->deletable = deletable; 
    565580    l->callback = callback; 
    566581    l->allow_duplicates = TRUE; 
    listbox_select_last (WListbox * l) 
    648663void 
    649664listbox_select_entry (WListbox * l, int dest) 
    650665{ 
     666    WLEntry *e; 
    651667    GList *le; 
    652668    int pos; 
    653669    gboolean top_seen = FALSE; 
    654670 
    655671    if (listbox_is_empty (l) || dest < 0) 
     672    { 
     673        /* Reset position to a minimal one. */ 
     674        l->pos = 0; 
     675        l->virtual_pos = 0; 
    656676        return; 
     677    } 
    657678 
    658679    /* Special case */ 
    659680    for (pos = 0, le = g_queue_peek_head_link (l->list); le != NULL; pos++, le = g_list_next (le)) 
    listbox_select_entry (WListbox * l, int dest) 
    673694                if (l->pos - l->top >= lines) 
    674695                    l->top = l->pos - lines + 1; 
    675696            } 
     697            /* 
     698             * Set the virtual position, i.e.: a position in the initial, unfiltered list if the 
     699             * same element would be selected. 
     700             */ 
     701            e = LENTRY (le->data); 
     702            l->virtual_pos = e->index; 
    676703            return; 
    677704        } 
    678705    } 
    listbox_get_current (WListbox * l, char **string, void **extra) 
    701728    if (l != NULL) 
    702729        e = listbox_get_nth_item (l, l->pos); 
    703730 
    704     ok = (e != NULL); 
     731    ok = (e != NULL && e->index != -2); 
    705732 
    706733    if (string != NULL) 
    707734        *string = ok ? e->text : NULL; 
    listbox_get_nth_item (const WListbox * l, int pos) 
    720747        GList *item; 
    721748 
    722749        item = g_queue_peek_nth_link (l->list, (guint) pos); 
    723         if (item != NULL) 
     750        if (item != NULL && LENTRY (item->data)->index != -2) 
    724751            return LENTRY (item->data); 
    725752    } 
    726753 
    listbox_remove_list (WListbox * l) 
    802829 
    803830/* --------------------------------------------------------------------------------------------- */ 
    804831 
     832/* 
     833 * Initializes the listbox elements with their position index. This allows to alter (filter, in 
     834 * particular) the listbox elements order and still get the original index (when selecting an 
     835 * element). 
     836 */ 
     837void 
     838listbox_init_indices (WListbox * l) 
     839{ 
     840    int index = 0; 
     841    g_queue_foreach (l->list, listbox_foreach_apply_index, &index); 
     842} 
     843 
     844/* --------------------------------------------------------------------------------------------- */ 
     845 
    805846char * 
    806847listbox_add_item (WListbox * l, listbox_append_t pos, int hotkey, const char *text, void *data, 
    807848                  gboolean free_data) 
    listbox_add_item (WListbox * l, listbox_append_t pos, int hotkey, const char *te 
    815856        return NULL; 
    816857 
    817858    entry = g_new (WLEntry, 1); 
     859    entry->index = -1;          /* Will be initialized when switching to the filter state */ 
    818860    entry->text = g_strdup (text); 
     861    entry->free_text = 1; 
    819862    entry->data = data; 
    820863    entry->free_data = free_data; 
    821864    entry->hotkey = hotkey; 
  • lib/widget/listbox.h

    diff --git a/lib/widget/listbox.h b/lib/widget/listbox.h
    index 8b2236eff..53b3e0f45 100644
    a b typedef lcback_ret_t (*lcback_fn) (struct WListbox * l); 
    3535 
    3636typedef struct WLEntry 
    3737{ 
     38    int index;                  /* The location in the list (used when it's filtered) */ 
    3839    char *text;                 /* Text to display */ 
     40    gboolean free_text;         /* Whether to free the text on entry's removal */ 
    3941    int hotkey; 
    4042    void *data;                 /* Client information */ 
    4143    gboolean free_data;         /* Whether to free the data on entry's removal */ 
    typedef struct WListbox 
    4648    Widget widget; 
    4749    GQueue *list;               /* Pointer to the list of WLEntry */ 
    4850    int pos;                    /* The current element displayed */ 
     51    int virtual_pos;            /* The initial index of the current element, works also for filtered listbox */ 
    4952    int top;                    /* The first element displayed */ 
    5053    gboolean allow_duplicates;  /* Do we allow duplicates on the list? */ 
    5154    gboolean scrollbar;         /* Draw a scrollbar? */ 
    extern const global_keymap_t *listbox_map; 
    6164/*** declarations of public functions ************************************************************/ 
    6265 
    6366WListbox *listbox_new (int y, int x, int height, int width, gboolean deletable, lcback_fn callback); 
     67 
    6468int listbox_search_text (WListbox * l, const char *text); 
    6569int listbox_search_data (WListbox * l, const void *data); 
    6670void listbox_select_first (WListbox * l); 
    void listbox_remove_current (WListbox * l); 
    7478gboolean listbox_is_empty (const WListbox * l); 
    7579void listbox_set_list (WListbox * l, GQueue * list); 
    7680void listbox_remove_list (WListbox * l); 
     81void listbox_init_indices (WListbox * l); 
    7782char *listbox_add_item (WListbox * l, listbox_append_t pos, int hotkey, const char *text, 
    7883                        void *data, gboolean free_data); 
    7984 
  • lib/widget/widget-common.c

    diff --git a/lib/widget/widget-common.c b/lib/widget/widget-common.c
    index e2fcd1222..8dd4a0d30 100644
    a b widget_init (Widget * w, int y, int x, int lines, int cols, 
    338338    w->find_by_type = widget_default_find_by_type; 
    339339    w->find_by_id = widget_default_find_by_id; 
    340340 
     341    w->pre_unlink_func = NULL; 
     342 
    341343    w->set_state = widget_default_set_state; 
    342344    w->get_colors = widget_default_get_colors; 
    343345} 
  • lib/widget/widget-common.h

    diff --git a/lib/widget/widget-common.h b/lib/widget/widget-common.h
    index a20bcd671..c58bddeae 100644
    a b typedef enum 
    4343    MSG_ACTION,                 /* Send to widget to handle command */ 
    4444    MSG_NOTIFY,                 /* Typically sent to dialog to inform it of state-change 
    4545                                 * of listboxes, check- and radiobuttons. */ 
     46    MSG_UPDATE_LIST,            /* Sent to listboxes to request the list regeneration (filtering) 
     47                                 * in the MultiSearch mode. */ 
    4648    MSG_CURSOR,                 /* Sent to widget to position the cursor */ 
    4749    MSG_IDLE,                   /* The idle state is active */ 
    4850    MSG_RESIZE,                 /* Screen size has changed */ 
    typedef enum 
    8890    WST_CONSTRUCT = (1 << 15),  /* Widget has been constructed but not run yet */ 
    8991    WST_ACTIVE = (1 << 16),     /* Dialog is visible and active */ 
    9092    WST_SUSPENDED = (1 << 17),  /* Dialog is suspended */ 
    91     WST_CLOSED = (1 << 18)      /* Dialog is closed */ 
     93    WST_CLOSED = (1 << 18),     /* Dialog is closed */ 
     94 
     95    WST_FILTER = (1 << 19)      /* Listbox is filtering its contents */ 
    9296} widget_state_t; 
    9397 
    9498/* Flags for widget repositioning on dialog resize */ 
    struct Widget 
    165169    cb_ret_t (*set_state) (Widget * w, widget_state_t state, gboolean enable); 
    166170    /* *INDENT-ON* */ 
    167171 
     172    GDestroyNotify pre_unlink_func;     /* a function invoked right before removing from a WGroup by 
     173                                         * group_remove_widget; it can unregister any events, what depends 
     174                                         * on the `event_group` field of the group; */ 
     175 
    168176    const int *(*get_colors) (const Widget * w); 
    169177}; 
    170178 
  • src/editor/choosesyntax.c

    diff --git a/src/editor/choosesyntax.c b/src/editor/choosesyntax.c
    index 09b6d75d5..71ec44e12 100644
    a b exec_edit_syntax_dialog (const GPtrArray * names, const char *current_syntax) 
    8484        name = g_ptr_array_index (names, i); 
    8585        LISTBOX_APPEND_TEXT (syntaxlist, 0, name, NULL, FALSE); 
    8686        if (current_syntax != NULL && strcmp (name, current_syntax) == 0) 
    87             listbox_select_entry (syntaxlist->list, i + N_DFLT_ENTRIES); 
     87            listbox_select_entry (LISTBOX (syntaxlist->list), i + N_DFLT_ENTRIES); 
    8888    } 
    8989 
    9090    return run_listbox (syntaxlist); 
  • src/editor/editcmd_dialogs.c

    diff --git a/src/editor/editcmd_dialogs.c b/src/editor/editcmd_dialogs.c
    index 8b3634f23..2bfb71900 100644
    a b editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** comp 
    351351    int start_x, start_y, offset, i; 
    352352    char *curr = NULL; 
    353353    WDialog *compl_dlg; 
    354     WListbox *compl_list; 
     354    WFilteringListbox *compl_list; 
     355    WListbox *lw; 
    355356    int compl_dlg_h;            /* completion dialog height */ 
    356357    int compl_dlg_w;            /* completion dialog width */ 
    357358 
    editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** comp 
    384385                    dialog_colors, NULL, NULL, "[Completion]", NULL); 
    385386 
    386387    /* create the listbox */ 
    387     compl_list = listbox_new (1, 1, compl_dlg_h - 2, compl_dlg_w - 2, FALSE, NULL); 
     388    compl_list = filtering_listbox_new (1, 1, compl_dlg_h - 2, compl_dlg_w - 2, FALSE, NULL, 
     389                                        FILT_LIST_DIALOG_AUTO_RESIZE); 
     390 
     391    /* Save WListbox pointer for convenience. */ 
     392    lw = LISTBOX (compl_list); 
    388393 
    389394    /* add the dialog */ 
    390395    group_add_widget (GROUP (compl_dlg), compl_list); 
    391396 
    392397    /* fill the listbox with the completions */ 
    393398    for (i = num_compl - 1; i >= 0; i--)        /* reverse order */ 
    394         listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, (char *) compl[i]->str, NULL, 
    395                           FALSE); 
     399        listbox_add_item (lw, LISTBOX_APPEND_AT_END, 0, (char *) compl[i]->str, NULL, FALSE); 
    396400 
    397401    /* pop up the dialog and apply the chosen completion */ 
    398402    if (dlg_run (compl_dlg) == B_ENTER) 
    399403    { 
    400         listbox_get_current (compl_list, &curr, NULL); 
     404        listbox_get_current (lw, &curr, NULL); 
    401405        curr = g_strdup (curr); 
    402406    } 
    403407 
  • src/editor/editwidget.c

    diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c
    index 18ac00e66..f1989114a 100644
    a b edit_window_list (const WDialog * h) 
    302302    Listbox *listbox; 
    303303    GList *w; 
    304304    WEdit *selected; 
     305    WListbox *lw; 
    305306    int i = 0; 
    306307 
    307308    lines = MIN ((size_t) (LINES * 2 / 3), dlg_num); 
    edit_window_list (const WDialog * h) 
    309310 
    310311    listbox = create_listbox_window (lines, cols, _("Open files"), "[Open files]"); 
    311312 
     313    /* Convenience variable. */ 
     314    lw = LISTBOX (listbox->list); 
     315 
    312316    for (w = g->widgets; w != NULL; w = g_list_next (w)) 
    313317        if (edit_widget_is_editor (CONST_WIDGET (w->data))) 
    314318        { 
    edit_window_list (const WDialog * h) 
    322326                    g_strdup_printf ("%c%s", e->modified ? '*' : ' ', 
    323327                                     vfs_path_as_str (e->filename_vpath)); 
    324328 
    325             listbox_add_item (listbox->list, LISTBOX_APPEND_AT_END, get_hotkey (i++), 
    326                               str_term_trim (fname, WIDGET (listbox->list)->cols - 2), e, FALSE); 
     329            listbox_add_item (lw, LISTBOX_APPEND_AT_END, get_hotkey (i++), 
     330                              str_term_trim (fname, WIDGET (lw)->cols - 2), e, FALSE); 
    327331            g_free (fname); 
    328332        } 
    329333 
  • src/file_history.c

    diff --git a/src/file_history.c b/src/file_history.c
    index 4304655aa..e5751ab8a 100644
    a b file_history_create_item (history_descriptor_t * hd, void *data) 
    155155    width = str_term_width1 (fhd->file_name); 
    156156    hd->max_width = MAX (width, hd->max_width); 
    157157 
    158     listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, fhd->file_name, fhd->file_pos, TRUE); 
     158    listbox_add_item (LISTBOX (hd->listbox), LISTBOX_APPEND_AT_END, 0, fhd->file_name, 
     159                      fhd->file_pos, TRUE); 
    159160    /* fhd->file_pos is not copied, NULLize it to prevent double free */ 
    160161    fhd->file_pos = NULL; 
    161162} 
  • src/keybind-defaults.c

    diff --git a/src/keybind-defaults.c b/src/keybind-defaults.c
    index 7b87c2f5a..2972e5bbf 100644
    a b static const global_keymap_ini_t default_listbox_keymap[] = { 
    293293    {"Bottom", "end; alt-gt; c1"}, 
    294294    {"PageUp", "pgup; alt-v"}, 
    295295    {"PageDown", "pgdn; ctrl-v"}, 
    296     {"Delete", "delete; d"}, 
    297     {"Clear", "shift-delete; shift-d"}, 
     296    {"Delete", "delete"}, 
     297    {"Clear", "shift-delete"}, 
    298298    {"View", "f3"}, 
    299299    {"Edit", "f4"}, 
     300    {"MultiSearch", "alt-space; ctrl-space"}, 
    300301    {"Enter", "enter"}, 
    301302    {NULL, NULL} 
    302303}; 
  • src/selcodepage.c

    diff --git a/src/selcodepage.c b/src/selcodepage.c
    index eba9d25bb..9ce48325b 100644
    a b select_charset (int center_y, int center_x, int current_charset, gboolean seldis 
    107107        ? ((current_charset < 0) ? codepages->len : (size_t) current_charset) 
    108108        : ((size_t) current_charset + 1); 
    109109 
    110     listbox_select_entry (listbox->list, i); 
     110    listbox_select_entry (LISTBOX (listbox->list), i); 
    111111 
    112112    listbox_result = run_listbox (listbox); 
    113113 
  • src/usermenu.c

    diff --git a/src/usermenu.c b/src/usermenu.c
    index 1fecbeaac..ba10634ab 100644
    a b user_menu_cmd (const WEdit * edit_widget, const char *menu_file, int selected_en 
    11221122                                     extract_line (p, p + MAX_ENTRY_LEN), p, FALSE); 
    11231123            } 
    11241124            /* Select the default entry */ 
    1125             listbox_select_entry (listbox->list, selected); 
     1125            listbox_select_entry (LISTBOX (listbox->list), selected); 
    11261126 
    11271127            selected = run_listbox (listbox); 
    11281128        }