From ffccd5b2b05243e7976db80f90f453dccfae9886 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 22:22:03 +0200 Subject: Adding upstream version 3:4.8.30. Signed-off-by: Daniel Baumann --- src/filemanager/filemanager.c | 1852 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1852 insertions(+) create mode 100644 src/filemanager/filemanager.c (limited to 'src/filemanager/filemanager.c') diff --git a/src/filemanager/filemanager.c b/src/filemanager/filemanager.c new file mode 100644 index 0000000..b995024 --- /dev/null +++ b/src/filemanager/filemanager.c @@ -0,0 +1,1852 @@ +/* + Main dialog (file panels) of the Midnight Commander + + Copyright (C) 1994-2023 + Free Software Foundation, Inc. + + Written by: + Miguel de Icaza, 1994, 1995, 1996, 1997 + Janne Kukonlehto, 1994, 1995 + Norbert Warmuth, 1997 + Andrew Borodin , 2009-2022 + Slava Zanko , 2013 + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/** \file filemanager.c + * \brief Source: main dialog (file panels) of the Midnight Commander + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for username in xterm title */ + +#include "lib/global.h" +#include "lib/fileloc.h" /* MC_HINT */ + +#include "lib/tty/tty.h" +#include "lib/tty/key.h" /* KEY_M_* masks */ +#include "lib/skin.h" +#include "lib/util.h" + +#include "lib/vfs/vfs.h" + +#include "src/args.h" +#ifdef ENABLE_SUBSHELL +#include "src/subshell/subshell.h" +#endif +#include "src/execute.h" /* toggle_subshell */ +#include "src/setup.h" /* variables */ +#include "src/learn.h" /* learn_keys() */ +#include "src/keymap.h" +#include "lib/fileloc.h" /* MC_FILEPOS_FILE */ +#include "lib/keybind.h" +#include "lib/event.h" + +#include "tree.h" +#include "boxes.h" /* sort_box(), tree_box() */ +#include "layout.h" +#include "cmd.h" /* commands */ +#include "hotlist.h" +#include "panelize.h" +#include "command.h" /* cmdline */ +#include "dir.h" /* dir_list_clean() */ + +#ifdef USE_INTERNAL_EDIT +#include "src/editor/edit.h" +#endif + +#ifdef USE_DIFF_VIEW +#include "src/diffviewer/ydiff.h" +#endif + +#include "src/consaver/cons.saver.h" /* show_console_contents */ +#include "src/file_history.h" /* show_file_history() */ + +#include "filemanager.h" + +/*** global variables ****************************************************************************/ + +/* When the modes are active, left_panel, right_panel and tree_panel */ +/* point to a proper data structure. You should check with the functions */ +/* get_current_type and get_other_type the types of the panels before using */ +/* this pointer variables */ + +/* The structures for the panels */ +WPanel *left_panel = NULL; +WPanel *right_panel = NULL; +/* Pointer to the selected and unselected panel */ +WPanel *current_panel = NULL; + +/* The Menubar */ +WMenuBar *the_menubar = NULL; +/* The widget where we draw the prompt */ +WLabel *the_prompt; +/* The hint bar */ +WLabel *the_hint; +/* The button bar */ +WButtonBar *the_bar; + +/* The prompt */ +const char *mc_prompt = NULL; + +/*** file scope macro definitions ****************************************************************/ + +#ifdef HAVE_CHARSET +/* + * Don't restrict the output on the screen manager level, + * the translation tables take care of it. + */ +#endif /* !HAVE_CHARSET */ + +/*** file scope type declarations ****************************************************************/ + +/*** forward declarations (file scope functions) *************************************************/ + +/*** file scope variables ************************************************************************/ + +static menu_t *left_menu, *right_menu; + +/* --------------------------------------------------------------------------------------------- */ +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +/** Stop MC main dialog and the current dialog if it exists. + * Needed to provide fast exit from MC viewer or editor on shell exit */ +static void +stop_dialogs (void) +{ + dlg_close (filemanager); + + if (top_dlg != NULL) + dlg_close (DIALOG (top_dlg->data)); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +treebox_cmd (void) +{ + char *sel_dir; + + sel_dir = tree_box (panel_current_entry (current_panel)->fname->str); + if (sel_dir != NULL) + { + vfs_path_t *sel_vdir; + + sel_vdir = vfs_path_from_str (sel_dir); + panel_cd (current_panel, sel_vdir, cd_exact); + vfs_path_free (sel_vdir, TRUE); + g_free (sel_dir); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef LISTMODE_EDITOR +static void +listmode_cmd (void) +{ + char *newmode; + + if (get_current_type () != view_listing) + return; + + newmode = listmode_edit (current_panel->user_format); + if (!newmode) + return; + + g_free (current_panel->user_format); + current_panel->list_format = list_user; + current_panel->user_format = newmode; + set_panel_formats (current_panel); + + do_refresh (); +} +#endif /* LISTMODE_EDITOR */ + +/* --------------------------------------------------------------------------------------------- */ + +static GList * +create_panel_menu (void) +{ + GList *entries = NULL; + + entries = g_list_prepend (entries, menu_entry_new (_("File listin&g"), CK_PanelListing)); + entries = g_list_prepend (entries, menu_entry_new (_("&Quick view"), CK_PanelQuickView)); + entries = g_list_prepend (entries, menu_entry_new (_("&Info"), CK_PanelInfo)); + entries = g_list_prepend (entries, menu_entry_new (_("&Tree"), CK_PanelTree)); + entries = g_list_prepend (entries, menu_separator_new ()); + entries = + g_list_prepend (entries, menu_entry_new (_("&Listing format..."), CK_SetupListingFormat)); + entries = g_list_prepend (entries, menu_entry_new (_("&Sort order..."), CK_Sort)); + entries = g_list_prepend (entries, menu_entry_new (_("&Filter..."), CK_Filter)); +#ifdef HAVE_CHARSET + entries = g_list_prepend (entries, menu_entry_new (_("&Encoding..."), CK_SelectCodepage)); +#endif + entries = g_list_prepend (entries, menu_separator_new ()); +#ifdef ENABLE_VFS_FTP + entries = g_list_prepend (entries, menu_entry_new (_("FT&P link..."), CK_ConnectFtp)); +#endif +#ifdef ENABLE_VFS_FISH + entries = g_list_prepend (entries, menu_entry_new (_("S&hell link..."), CK_ConnectFish)); +#endif +#ifdef ENABLE_VFS_SFTP + entries = g_list_prepend (entries, menu_entry_new (_("SFTP li&nk..."), CK_ConnectSftp)); +#endif + entries = g_list_prepend (entries, menu_entry_new (_("Paneli&ze"), CK_Panelize)); + entries = g_list_prepend (entries, menu_separator_new ()); + entries = g_list_prepend (entries, menu_entry_new (_("&Rescan"), CK_Reread)); + + return g_list_reverse (entries); +} + +/* --------------------------------------------------------------------------------------------- */ + +static GList * +create_file_menu (void) +{ + GList *entries = NULL; + + entries = g_list_prepend (entries, menu_entry_new (_("&View"), CK_View)); + entries = g_list_prepend (entries, menu_entry_new (_("Vie&w file..."), CK_ViewFile)); + entries = g_list_prepend (entries, menu_entry_new (_("&Filtered view"), CK_ViewFiltered)); + entries = g_list_prepend (entries, menu_entry_new (_("&Edit"), CK_Edit)); + entries = g_list_prepend (entries, menu_entry_new (_("&Copy"), CK_Copy)); + entries = g_list_prepend (entries, menu_entry_new (_("C&hmod"), CK_ChangeMode)); + entries = g_list_prepend (entries, menu_entry_new (_("&Link"), CK_Link)); + entries = g_list_prepend (entries, menu_entry_new (_("&Symlink"), CK_LinkSymbolic)); + entries = + g_list_prepend (entries, menu_entry_new (_("Relative symlin&k"), CK_LinkSymbolicRelative)); + entries = g_list_prepend (entries, menu_entry_new (_("Edit s&ymlink"), CK_LinkSymbolicEdit)); + entries = g_list_prepend (entries, menu_entry_new (_("Ch&own"), CK_ChangeOwn)); + entries = g_list_prepend (entries, menu_entry_new (_("&Advanced chown"), CK_ChangeOwnAdvanced)); +#ifdef ENABLE_EXT2FS_ATTR + entries = g_list_prepend (entries, menu_entry_new (_("Cha&ttr"), CK_ChangeAttributes)); +#endif + entries = g_list_prepend (entries, menu_entry_new (_("&Rename/Move"), CK_Move)); + entries = g_list_prepend (entries, menu_entry_new (_("&Mkdir"), CK_MakeDir)); + entries = g_list_prepend (entries, menu_entry_new (_("&Delete"), CK_Delete)); + entries = g_list_prepend (entries, menu_entry_new (_("&Quick cd"), CK_CdQuick)); + entries = g_list_prepend (entries, menu_separator_new ()); + entries = g_list_prepend (entries, menu_entry_new (_("Select &group"), CK_Select)); + entries = g_list_prepend (entries, menu_entry_new (_("U&nselect group"), CK_Unselect)); + entries = g_list_prepend (entries, menu_entry_new (_("&Invert selection"), CK_SelectInvert)); + entries = g_list_prepend (entries, menu_separator_new ()); + entries = g_list_prepend (entries, menu_entry_new (_("E&xit"), CK_Quit)); + + return g_list_reverse (entries); +} + +/* --------------------------------------------------------------------------------------------- */ + +static GList * +create_command_menu (void) +{ + /* I know, I'm lazy, but the tree widget when it's not running + * as a panel still has some problems, I have not yet finished + * the WTree widget port, sorry. + */ + GList *entries = NULL; + + entries = g_list_prepend (entries, menu_entry_new (_("&User menu"), CK_UserMenu)); + entries = g_list_prepend (entries, menu_entry_new (_("&Directory tree"), CK_Tree)); + entries = g_list_prepend (entries, menu_entry_new (_("&Find file"), CK_Find)); + entries = g_list_prepend (entries, menu_entry_new (_("S&wap panels"), CK_Swap)); + entries = g_list_prepend (entries, menu_entry_new (_("Switch &panels on/off"), CK_Shell)); + entries = g_list_prepend (entries, menu_entry_new (_("&Compare directories"), CK_CompareDirs)); +#ifdef USE_DIFF_VIEW + entries = g_list_prepend (entries, menu_entry_new (_("C&ompare files"), CK_CompareFiles)); +#endif + entries = + g_list_prepend (entries, menu_entry_new (_("E&xternal panelize"), CK_ExternalPanelize)); + entries = g_list_prepend (entries, menu_entry_new (_("Show directory s&izes"), CK_DirSize)); + entries = g_list_prepend (entries, menu_separator_new ()); + entries = g_list_prepend (entries, menu_entry_new (_("Command &history"), CK_History)); + entries = + g_list_prepend (entries, + menu_entry_new (_("Viewed/edited files hi&story"), CK_EditorViewerHistory)); + entries = g_list_prepend (entries, menu_entry_new (_("Di&rectory hotlist"), CK_HotList)); +#ifdef ENABLE_VFS + entries = g_list_prepend (entries, menu_entry_new (_("&Active VFS list"), CK_VfsList)); +#endif +#ifdef ENABLE_BACKGROUND + entries = g_list_prepend (entries, menu_entry_new (_("&Background jobs"), CK_Jobs)); +#endif + entries = g_list_prepend (entries, menu_entry_new (_("Screen lis&t"), CK_ScreenList)); + entries = g_list_prepend (entries, menu_separator_new ()); +#ifdef ENABLE_VFS_UNDELFS + entries = + g_list_prepend (entries, menu_entry_new (_("&Undelete files (ext2fs only)"), CK_Undelete)); +#endif +#ifdef LISTMODE_EDITOR + entries = g_list_prepend (entries, menu_entry_new (_("&Listing format edit"), CK_ListMode)); +#endif +#if defined (ENABLE_VFS_UNDELFS) || defined (LISTMODE_EDITOR) + entries = g_list_prepend (entries, menu_separator_new ()); +#endif + entries = + g_list_prepend (entries, menu_entry_new (_("Edit &extension file"), CK_EditExtensionsFile)); + entries = g_list_prepend (entries, menu_entry_new (_("Edit &menu file"), CK_EditUserMenu)); + entries = + g_list_prepend (entries, + menu_entry_new (_("Edit hi&ghlighting group file"), + CK_EditFileHighlightFile)); + + return g_list_reverse (entries); +} + +/* --------------------------------------------------------------------------------------------- */ + +static GList * +create_options_menu (void) +{ + GList *entries = NULL; + + entries = g_list_prepend (entries, menu_entry_new (_("&Configuration..."), CK_Options)); + entries = g_list_prepend (entries, menu_entry_new (_("&Layout..."), CK_OptionsLayout)); + entries = g_list_prepend (entries, menu_entry_new (_("&Panel options..."), CK_OptionsPanel)); + entries = g_list_prepend (entries, menu_entry_new (_("C&onfirmation..."), CK_OptionsConfirm)); + entries = g_list_prepend (entries, menu_entry_new (_("&Appearance..."), CK_OptionsAppearance)); + entries = + g_list_prepend (entries, menu_entry_new (_("&Display bits..."), CK_OptionsDisplayBits)); + entries = g_list_prepend (entries, menu_entry_new (_("Learn &keys..."), CK_LearnKeys)); +#ifdef ENABLE_VFS + entries = g_list_prepend (entries, menu_entry_new (_("&Virtual FS..."), CK_OptionsVfs)); +#endif + entries = g_list_prepend (entries, menu_separator_new ()); + entries = g_list_prepend (entries, menu_entry_new (_("&Save setup"), CK_SaveSetup)); + + return g_list_reverse (entries); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +init_menu (void) +{ + left_menu = menu_new ("", create_panel_menu (), "[Left and Right Menus]"); + menubar_add_menu (the_menubar, left_menu); + menubar_add_menu (the_menubar, menu_new (_("&File"), create_file_menu (), "[File Menu]")); + menubar_add_menu (the_menubar, + menu_new (_("&Command"), create_command_menu (), "[Command Menu]")); + menubar_add_menu (the_menubar, + menu_new (_("&Options"), create_options_menu (), "[Options Menu]")); + right_menu = menu_new ("", create_panel_menu (), "[Left and Right Menus]"); + menubar_add_menu (the_menubar, right_menu); + update_menu (); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +menu_last_selected_cmd (void) +{ + menubar_activate (the_menubar, drop_menus, -1); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +menu_cmd (void) +{ + int selected; + + if ((get_current_index () == 0) == current_panel->active) + selected = 0; + else + selected = g_list_length (the_menubar->menu) - 1; + + menubar_activate (the_menubar, drop_menus, selected); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +sort_cmd (void) +{ + WPanel *p; + const panel_field_t *sort_order; + + if (!SELECTED_IS_PANEL) + return; + + p = MENU_PANEL; + sort_order = sort_box (&p->sort_info, p->sort_field); + panel_set_sort_order (p, sort_order); +} + +/* --------------------------------------------------------------------------------------------- */ + +static char * +midnight_get_shortcut (long command) +{ + const char *ext_map; + const char *shortcut = NULL; + + shortcut = keybind_lookup_keymap_shortcut (filemanager_map, command); + if (shortcut != NULL) + return g_strdup (shortcut); + + shortcut = keybind_lookup_keymap_shortcut (panel_map, command); + if (shortcut != NULL) + return g_strdup (shortcut); + + ext_map = keybind_lookup_keymap_shortcut (filemanager_map, CK_ExtendedKeyMap); + if (ext_map != NULL) + shortcut = keybind_lookup_keymap_shortcut (filemanager_x_map, command); + if (shortcut != NULL) + return g_strdup_printf ("%s %s", ext_map, shortcut); + + return NULL; +} + +/* --------------------------------------------------------------------------------------------- */ + +static char * +midnight_get_title (const WDialog * h, size_t len) +{ + char *path; + char *login; + char *p; + + (void) h; + + title_path_prepare (&path, &login); + + p = g_strdup_printf ("%s [%s]:%s", _("Panels:"), login, path); + g_free (path); + g_free (login); + path = g_strdup (str_trunc (p, len - 4)); + g_free (p); + + return path; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +toggle_panels_split (void) +{ + panels_layout.horizontal_split = !panels_layout.horizontal_split; + layout_change (); + do_refresh (); +} + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef ENABLE_VFS +/* event helper */ +static gboolean +check_panel_timestamp (const WPanel * panel, panel_view_mode_t mode, struct vfs_class *vclass, + vfsid id) +{ + if (mode == view_listing) + { + const struct vfs_class *me; + + me = vfs_path_get_last_path_vfs (panel->cwd_vpath); + if (me != vclass) + return FALSE; + + if (vfs_getid (panel->cwd_vpath) != id) + return FALSE; + } + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +/* event callback */ +static gboolean +check_current_panel_timestamp (const gchar * event_group_name, const gchar * event_name, + gpointer init_data, gpointer data) +{ + ev_vfs_stamp_create_t *event_data = (ev_vfs_stamp_create_t *) data; + + (void) event_group_name; + (void) event_name; + (void) init_data; + + event_data->ret = + check_panel_timestamp (current_panel, get_current_type (), event_data->vclass, + event_data->id); + return !event_data->ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +/* event callback */ +static gboolean +check_other_panel_timestamp (const gchar * event_group_name, const gchar * event_name, + gpointer init_data, gpointer data) +{ + ev_vfs_stamp_create_t *event_data = (ev_vfs_stamp_create_t *) data; + + (void) event_group_name; + (void) event_name; + (void) init_data; + + event_data->ret = + check_panel_timestamp (other_panel, get_other_type (), event_data->vclass, event_data->id); + return !event_data->ret; +} +#endif /* ENABLE_VFS */ + +/* --------------------------------------------------------------------------------------------- */ + +/* event callback */ +static gboolean +print_vfs_message (const gchar * event_group_name, const gchar * event_name, + gpointer init_data, gpointer data) +{ + ev_vfs_print_message_t *event_data = (ev_vfs_print_message_t *) data; + + (void) event_group_name; + (void) event_name; + (void) init_data; + + if (mc_global.midnight_shutdown) + goto ret; + + if (!mc_global.message_visible || the_hint == NULL || WIDGET (the_hint)->owner == NULL) + { + int col, row; + + if (!nice_rotating_dash || (ok_to_refresh <= 0)) + goto ret; + + /* Preserve current cursor position */ + tty_getyx (&row, &col); + + tty_gotoyx (0, 0); + tty_setcolor (NORMAL_COLOR); + tty_print_string (str_fit_to_term (event_data->msg, COLS - 1, J_LEFT)); + + /* Restore cursor position */ + tty_gotoyx (row, col); + mc_refresh (); + goto ret; + } + + if (mc_global.message_visible) + set_hintbar (event_data->msg); + + ret: + MC_PTR_FREE (event_data->msg); + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +create_panels (void) +{ + int current_index, other_index; + panel_view_mode_t current_mode, other_mode; + char *current_dir, *other_dir; + vfs_path_t *original_dir; + + /* + * Following cases from command line are possible: + * 'mc' (no arguments): mc_run_param0 == NULL, mc_run_param1 == NULL + * active panel uses current directory + * passive panel uses "other_dir" from panels.ini + * + * 'mc dir1 dir2' (two arguments): mc_run_param0 != NULL, mc_run_param1 != NULL + * active panel uses mc_run_param0 + * passive panel uses mc_run_param1 + * + * 'mc dir1' (single argument): mc_run_param0 != NULL, mc_run_param1 == NULL + * active panel uses mc_run_param0 + * passive panel uses "other_dir" from panels.ini + */ + + /* Set up panel directories */ + if (boot_current_is_left) + { + /* left panel is active */ + current_index = 0; + other_index = 1; + current_mode = startup_left_mode; + other_mode = startup_right_mode; + + if (mc_run_param0 == NULL && mc_run_param1 == NULL) + { + /* no arguments */ + current_dir = NULL; /* assume current dir */ + other_dir = saved_other_dir; /* from ini */ + } + else if (mc_run_param0 != NULL && mc_run_param1 != NULL) + { + /* two arguments */ + current_dir = (char *) mc_run_param0; + other_dir = mc_run_param1; + } + else /* mc_run_param0 != NULL && mc_run_param1 == NULL */ + { + /* one argument */ + current_dir = (char *) mc_run_param0; + other_dir = saved_other_dir; /* from ini */ + } + } + else + { + /* right panel is active */ + current_index = 1; + other_index = 0; + current_mode = startup_right_mode; + other_mode = startup_left_mode; + + if (mc_run_param0 == NULL && mc_run_param1 == NULL) + { + /* no arguments */ + current_dir = NULL; /* assume current dir */ + other_dir = saved_other_dir; /* from ini */ + } + else if (mc_run_param0 != NULL && mc_run_param1 != NULL) + { + /* two arguments */ + current_dir = (char *) mc_run_param0; + other_dir = mc_run_param1; + } + else /* mc_run_param0 != NULL && mc_run_param1 == NULL */ + { + /* one argument */ + current_dir = (char *) mc_run_param0; + other_dir = saved_other_dir; /* from ini */ + } + } + + /* 1. Get current dir */ + original_dir = vfs_path_clone (vfs_get_raw_current_dir ()); + + /* 2. Create passive panel */ + if (other_dir != NULL) + { + vfs_path_t *vpath; + + if (g_path_is_absolute (other_dir)) + vpath = vfs_path_from_str (other_dir); + else + vpath = vfs_path_append_new (original_dir, other_dir, (char *) NULL); + mc_chdir (vpath); + vfs_path_free (vpath, TRUE); + } + create_panel (other_index, other_mode); + + /* 3. Create active panel */ + if (current_dir == NULL) + mc_chdir (original_dir); + else + { + vfs_path_t *vpath; + + if (g_path_is_absolute (current_dir)) + vpath = vfs_path_from_str (current_dir); + else + vpath = vfs_path_append_new (original_dir, current_dir, (char *) NULL); + mc_chdir (vpath); + vfs_path_free (vpath, TRUE); + } + create_panel (current_index, current_mode); + + if (startup_left_mode == view_listing) + current_panel = left_panel; + else if (right_panel != NULL) + current_panel = right_panel; + else + current_panel = left_panel; + + vfs_path_free (original_dir, TRUE); + +#ifdef ENABLE_VFS + mc_event_add (MCEVENT_GROUP_CORE, "vfs_timestamp", check_other_panel_timestamp, NULL, NULL); + mc_event_add (MCEVENT_GROUP_CORE, "vfs_timestamp", check_current_panel_timestamp, NULL, NULL); +#endif /* ENABLE_VFS */ + + mc_event_add (MCEVENT_GROUP_CORE, "vfs_print_message", print_vfs_message, NULL, NULL); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +midnight_put_panel_path (WPanel * panel) +{ + vfs_path_t *cwd_vpath; + const char *cwd_vpath_str; + + if (!command_prompt) + return; + +#ifdef HAVE_CHARSET + cwd_vpath = remove_encoding_from_path (panel->cwd_vpath); +#else + cwd_vpath = vfs_path_clone (panel->cwd_vpath); +#endif + + cwd_vpath_str = vfs_path_as_str (cwd_vpath); + + command_insert (cmdline, cwd_vpath_str, FALSE); + + if (!IS_PATH_SEP (cwd_vpath_str[strlen (cwd_vpath_str) - 1])) + command_insert (cmdline, PATH_SEP_STR, FALSE); + + vfs_path_free (cwd_vpath, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +put_link (WPanel * panel) +{ + const file_entry_t *fe; + + if (!command_prompt) + return; + + fe = panel_current_entry (panel); + + if (S_ISLNK (fe->st.st_mode)) + { + char buffer[MC_MAXPATHLEN]; + vfs_path_t *vpath; + int i; + + vpath = vfs_path_append_new (panel->cwd_vpath, fe->fname->str, (char *) NULL); + i = mc_readlink (vpath, buffer, sizeof (buffer) - 1); + vfs_path_free (vpath, TRUE); + + if (i > 0) + { + buffer[i] = '\0'; + command_insert (cmdline, buffer, TRUE); + } + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +put_current_link (void) +{ + put_link (current_panel); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +put_other_link (void) +{ + if (get_other_type () == view_listing) + put_link (other_panel); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** Insert the selected file name into the input line */ +static void +put_current_selected (void) +{ + const char *tmp; + + if (!command_prompt) + return; + + if (get_current_type () == view_tree) + { + WTree *tree; + const vfs_path_t *selected_name; + + tree = (WTree *) get_panel_widget (get_current_index ()); + selected_name = tree_selected_name (tree); + tmp = vfs_path_as_str (selected_name); + } + else + tmp = panel_current_entry (current_panel)->fname->str; + + command_insert (cmdline, tmp, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +put_tagged (WPanel * panel) +{ + if (!command_prompt) + return; + input_disable_update (cmdline); + if (panel->marked) + { + int i; + + for (i = 0; i < panel->dir.len; i++) + if (panel->dir.list[i].f.marked != 0) + command_insert (cmdline, panel->dir.list[i].fname->str, TRUE); + } + else + command_insert (cmdline, panel_current_entry (panel)->fname->str, TRUE); + + input_enable_update (cmdline); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +put_current_tagged (void) +{ + put_tagged (current_panel); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +put_other_tagged (void) +{ + if (get_other_type () == view_listing) + put_tagged (other_panel); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +setup_mc (void) +{ +#ifdef HAVE_SLANG +#ifdef HAVE_CHARSET + tty_display_8bit (TRUE); +#else + tty_display_8bit (mc_global.full_eight_bits); +#endif /* HAVE_CHARSET */ + +#else /* HAVE_SLANG */ + +#ifdef HAVE_CHARSET + tty_display_8bit (TRUE); +#else + tty_display_8bit (mc_global.eight_bit_clean); +#endif /* HAVE_CHARSET */ +#endif /* HAVE_SLANG */ + + if ((tty_baudrate () < 9600) || mc_global.tty.slow_terminal) + verbose = FALSE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +setup_dummy_mc (void) +{ + vfs_path_t *vpath; + char *d; + int ret; + + d = vfs_get_cwd (); + setup_mc (); + vpath = vfs_path_from_str (d); + ret = mc_chdir (vpath); + (void) ret; + vfs_path_free (vpath, TRUE); + g_free (d); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +done_mc (void) +{ + /* Setup shutdown + * + * We sync the profiles since the hotlist may have changed, while + * we only change the setup data if we have the auto save feature set + */ + + save_setup (auto_save_setup, panels_options.auto_save_setup); + + vfs_stamp_path (vfs_get_raw_current_dir ()); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +create_file_manager (void) +{ + Widget *w = WIDGET (filemanager); + WGroup *g = GROUP (filemanager); + + w->keymap = filemanager_map; + w->ext_keymap = filemanager_x_map; + + filemanager->get_shortcut = midnight_get_shortcut; + filemanager->get_title = midnight_get_title; + /* allow rebind tab */ + widget_want_tab (w, TRUE); + + the_menubar = menubar_new (NULL); + group_add_widget (g, the_menubar); + init_menu (); + + create_panels (); + group_add_widget (g, get_panel_widget (0)); + group_add_widget (g, get_panel_widget (1)); + + the_hint = label_new (0, 0, NULL); + the_hint->transparent = TRUE; + the_hint->auto_adjust_cols = 0; + WIDGET (the_hint)->rect.cols = COLS; + group_add_widget (g, the_hint); + + cmdline = command_new (0, 0, 0); + group_add_widget (g, cmdline); + + the_prompt = label_new (0, 0, mc_prompt); + the_prompt->transparent = TRUE; + group_add_widget (g, the_prompt); + + the_bar = buttonbar_new (); + group_add_widget (g, the_bar); + midnight_set_buttonbar (the_bar); + +#ifdef ENABLE_SUBSHELL + /* Must be done after creation of cmdline and prompt widgets to avoid potential + NULL dereference in load_prompt() -> ... -> setup_cmdline() -> label_set_text(). */ + if (mc_global.tty.use_subshell) + add_select_channel (mc_global.tty.subshell_pty, load_prompt, NULL); +#endif /* !ENABLE_SUBSHELL */ +} + +/* --------------------------------------------------------------------------------------------- */ + +/** result must be free'd (I think this should go in util.c) */ +static vfs_path_t * +prepend_cwd_on_local (const char *filename) +{ + vfs_path_t *vpath; + + vpath = vfs_path_from_str (filename); + if (!vfs_file_is_local (vpath) || g_path_is_absolute (filename)) + return vpath; + + vfs_path_free (vpath, TRUE); + + return vfs_path_append_new (vfs_get_raw_current_dir (), filename, (char *) NULL); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** Invoke the internal view/edit routine with: + * the default processing and forcing the internal viewer/editor + */ +static gboolean +mc_maybe_editor_or_viewer (void) +{ + gboolean ret; + + switch (mc_global.mc_run_mode) + { +#ifdef USE_INTERNAL_EDIT + case MC_RUN_EDITOR: + ret = edit_files ((GList *) mc_run_param0); + break; +#endif /* USE_INTERNAL_EDIT */ + case MC_RUN_VIEWER: + { + vfs_path_t *vpath = NULL; + + if (mc_run_param0 != NULL && *(char *) mc_run_param0 != '\0') + vpath = prepend_cwd_on_local ((char *) mc_run_param0); + + ret = view_file (vpath, FALSE, TRUE); + vfs_path_free (vpath, TRUE); + break; + } +#ifdef USE_DIFF_VIEW + case MC_RUN_DIFFVIEWER: + ret = dview_diff_cmd (mc_run_param0, mc_run_param1); + break; +#endif /* USE_DIFF_VIEW */ + default: + ret = FALSE; + } + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +show_editor_viewer_history (void) +{ + char *s; + int act; + + s = show_file_history (WIDGET (filemanager), &act); + if (s != NULL) + { + vfs_path_t *s_vpath; + + switch (act) + { + case CK_Edit: + s_vpath = vfs_path_from_str (s); + edit_file_at_line (s_vpath, use_internal_edit, 0); + break; + + case CK_View: + s_vpath = vfs_path_from_str (s); + view_file (s_vpath, use_internal_view, FALSE); + break; + + default: + { + char *d; + + d = g_path_get_dirname (s); + s_vpath = vfs_path_from_str (d); + panel_cd (current_panel, s_vpath, cd_exact); + panel_set_current_by_name (current_panel, s); + g_free (d); + } + } + + g_free (s); + vfs_path_free (s_vpath, TRUE); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +quit_cmd_internal (int quiet) +{ + int q = quit; + size_t n; + + n = dialog_switch_num () - 1; + if (n != 0) + { + char msg[BUF_MEDIUM]; + + g_snprintf (msg, sizeof (msg), + ngettext ("You have %zu opened screen. Quit anyway?", + "You have %zu opened screens. Quit anyway?", n), n); + + if (query_dialog (_("The Midnight Commander"), msg, D_NORMAL, 2, _("&Yes"), _("&No")) != 0) + return FALSE; + q = 1; + } + else if (quiet || !confirm_exit) + q = 1; + else if (query_dialog (_("The Midnight Commander"), + _("Do you really want to quit the Midnight Commander?"), + D_NORMAL, 2, _("&Yes"), _("&No")) == 0) + q = 1; + + if (q != 0) + { +#ifdef ENABLE_SUBSHELL + if (!mc_global.tty.use_subshell) + stop_dialogs (); + else if ((q = exit_subshell ()? 1 : 0) != 0) +#endif + stop_dialogs (); + } + + if (q != 0) + quit |= 1; + return (quit != 0); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +quit_cmd (void) +{ + return quit_cmd_internal (0); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** + * Repaint the contents of the panels without frames. To schedule panel + * for repainting, set panel->dirty to TRUE. There are many reasons why + * the panels need to be repainted, and this is a costly operation, so + * it's done once per event. + */ + +static void +update_dirty_panels (void) +{ + if (get_current_type () == view_listing && current_panel->dirty) + widget_draw (WIDGET (current_panel)); + + if (get_other_type () == view_listing && other_panel->dirty) + widget_draw (WIDGET (other_panel)); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +toggle_show_hidden (void) +{ + panels_options.show_dot_files = !panels_options.show_dot_files; + update_panels (UP_RELOAD, UP_KEEPSEL); + /* redraw panels forced */ + update_dirty_panels (); +} + +/* --------------------------------------------------------------------------------------------- */ + +static cb_ret_t +midnight_execute_cmd (Widget * sender, long command) +{ + cb_ret_t res = MSG_HANDLED; + + (void) sender; + + /* stop quick search before executing any command */ + send_message (current_panel, NULL, MSG_ACTION, CK_SearchStop, NULL); + + switch (command) + { + case CK_ChangePanel: + (void) change_panel (); + break; + case CK_HotListAdd: + add2hotlist_cmd (current_panel); + break; + case CK_SetupListingFormat: + setup_listing_format_cmd (); + break; + case CK_ChangeMode: + chmod_cmd (current_panel); + break; + case CK_ChangeOwn: + chown_cmd (current_panel); + break; + case CK_ChangeOwnAdvanced: + advanced_chown_cmd (current_panel); + break; +#ifdef ENABLE_EXT2FS_ATTR + case CK_ChangeAttributes: + chattr_cmd (current_panel); + break; +#endif + case CK_CompareDirs: + compare_dirs_cmd (); + break; + case CK_Options: + configure_box (); + break; +#ifdef ENABLE_VFS + case CK_OptionsVfs: + configure_vfs_box (); + break; +#endif + case CK_OptionsConfirm: + confirm_box (); + break; + case CK_Copy: + copy_cmd (current_panel); + break; + case CK_PutCurrentPath: + midnight_put_panel_path (current_panel); + break; + case CK_PutCurrentSelected: + put_current_selected (); + break; + case CK_PutCurrentFullSelected: + midnight_put_panel_path (current_panel); + put_current_selected (); + break; + case CK_PutCurrentLink: + put_current_link (); + break; + case CK_PutCurrentTagged: + put_current_tagged (); + break; + case CK_PutOtherPath: + if (get_other_type () == view_listing) + midnight_put_panel_path (other_panel); + break; + case CK_PutOtherLink: + put_other_link (); + break; + case CK_PutOtherTagged: + put_other_tagged (); + break; + case CK_Delete: + delete_cmd (current_panel); + break; + case CK_ScreenList: + dialog_switch_list (); + break; +#ifdef USE_DIFF_VIEW + case CK_CompareFiles: + diff_view_cmd (); + break; +#endif + case CK_OptionsDisplayBits: + display_bits_box (); + break; + case CK_Edit: + edit_cmd (current_panel); + break; +#ifdef USE_INTERNAL_EDIT + case CK_EditForceInternal: + edit_cmd_force_internal (current_panel); + break; +#endif + case CK_EditExtensionsFile: + ext_cmd (); + break; + case CK_EditFileHighlightFile: + edit_fhl_cmd (); + break; + case CK_EditUserMenu: + edit_mc_menu_cmd (); + break; + case CK_LinkSymbolicEdit: + edit_symlink_cmd (); + break; + case CK_ExternalPanelize: + external_panelize_cmd (); + break; + case CK_ViewFiltered: + view_filtered_cmd (current_panel); + break; + case CK_Find: + find_cmd (current_panel); + break; +#ifdef ENABLE_VFS_FISH + case CK_ConnectFish: + fishlink_cmd (); + break; +#endif +#ifdef ENABLE_VFS_FTP + case CK_ConnectFtp: + ftplink_cmd (); + break; +#endif +#ifdef ENABLE_VFS_SFTP + case CK_ConnectSftp: + sftplink_cmd (); + break; +#endif + case CK_Panelize: + panel_panelize_cd (); + break; + case CK_Help: + help_cmd (); + break; + case CK_History: + /* show the history of command line widget */ + send_message (cmdline, NULL, MSG_ACTION, CK_History, NULL); + break; + case CK_PanelInfo: + if (sender == WIDGET (the_menubar)) + info_cmd (); /* menu */ + else + info_cmd_no_menu (); /* shortcut or buttonbar */ + break; +#ifdef ENABLE_BACKGROUND + case CK_Jobs: + jobs_box (); + break; +#endif + case CK_OptionsLayout: + layout_box (); + break; + case CK_OptionsAppearance: + appearance_box (); + break; + case CK_LearnKeys: + learn_keys (); + break; + case CK_Link: + link_cmd (LINK_HARDLINK); + break; + case CK_PanelListing: + listing_cmd (); + break; +#ifdef LISTMODE_EDITOR + case CK_ListMode: + listmode_cmd (); + break; +#endif + case CK_Menu: + menu_cmd (); + break; + case CK_MenuLastSelected: + menu_last_selected_cmd (); + break; + case CK_MakeDir: + mkdir_cmd (current_panel); + break; + case CK_OptionsPanel: + panel_options_box (); + break; +#ifdef HAVE_CHARSET + case CK_SelectCodepage: + encoding_cmd (); + break; +#endif + case CK_CdQuick: + quick_cd_cmd (current_panel); + break; + case CK_HotList: + hotlist_cmd (current_panel); + break; + case CK_PanelQuickView: + if (sender == WIDGET (the_menubar)) + quick_view_cmd (); /* menu */ + else + quick_cmd_no_menu (); /* shortcut or buttonabr */ + break; + case CK_QuitQuiet: + quiet_quit_cmd (); + break; + case CK_Quit: + quit_cmd (); + break; + case CK_LinkSymbolicRelative: + link_cmd (LINK_SYMLINK_RELATIVE); + break; + case CK_Move: + rename_cmd (current_panel); + break; + case CK_Reread: + reread_cmd (); + break; +#ifdef ENABLE_VFS + case CK_VfsList: + vfs_list (current_panel); + break; +#endif + case CK_SaveSetup: + save_setup_cmd (); + break; + case CK_Select: + case CK_Unselect: + case CK_SelectInvert: + case CK_Filter: + res = send_message (current_panel, filemanager, MSG_ACTION, command, NULL); + break; + case CK_Shell: + toggle_subshell (); + break; + case CK_DirSize: + smart_dirsize_cmd (current_panel); + break; + case CK_Sort: + sort_cmd (); + break; + case CK_ExtendedKeyMap: + WIDGET (filemanager)->ext_mode = TRUE; + break; + case CK_Suspend: + mc_event_raise (MCEVENT_GROUP_CORE, "suspend", NULL); + break; + case CK_Swap: + swap_cmd (); + break; + case CK_LinkSymbolic: + link_cmd (LINK_SYMLINK_ABSOLUTE); + break; + case CK_ShowHidden: + toggle_show_hidden (); + break; + case CK_SplitVertHoriz: + toggle_panels_split (); + break; + case CK_SplitEqual: + panels_split_equal (); + break; + case CK_SplitMore: + panels_split_more (); + break; + case CK_SplitLess: + panels_split_less (); + break; + case CK_PanelTree: + panel_tree_cmd (); + break; + case CK_Tree: + treebox_cmd (); + break; +#ifdef ENABLE_VFS_UNDELFS + case CK_Undelete: + undelete_cmd (); + break; +#endif + case CK_UserMenu: + user_file_menu_cmd (); + break; + case CK_View: + view_cmd (current_panel); + break; + case CK_ViewFile: + view_file_cmd (current_panel); + break; + case CK_EditorViewerHistory: + show_editor_viewer_history (); + break; + case CK_Cancel: + /* don't close panels due to SIGINT */ + break; + default: + res = MSG_NOT_HANDLED; + } + + return res; +} + +/* --------------------------------------------------------------------------------------------- */ + +/** + * Whether the command-line should not respond to key events. + * + * This is TRUE if a QuickView or TreeView have the focus, as they're going + * to consume some keys and there's no sense in passing to the command-line + * just the leftovers. + */ +static gboolean +is_cmdline_mute (void) +{ + /* When one of panels is other than view_listing, + current_panel points to view_listing panel all time independently of + it's activity. Thus, we can't use get_current_type() here. + current_panel should point to actually current active panel + independently of it's type. */ + return (!current_panel->active + && (get_other_type () == view_quick || get_other_type () == view_tree)); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** + * Handles the Enter key on the command-line. + * + * Returns TRUE if non-whitespace was indeed processed. + */ +static gboolean +handle_cmdline_enter (void) +{ + const char *s; + + for (s = input_get_ctext (cmdline); *s != '\0' && whitespace (*s); s++) + ; + + if (*s != '\0') + { + send_message (cmdline, NULL, MSG_KEY, '\n', NULL); + return TRUE; + } + + input_insert (cmdline, "", FALSE); + cmdline->point = 0; + + return FALSE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static cb_ret_t +midnight_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) +{ + long command; + + switch (msg) + { + case MSG_INIT: + panel_init (); + setup_panels (); + return MSG_HANDLED; + + case MSG_DRAW: + load_hint (TRUE); + group_default_callback (w, NULL, MSG_DRAW, 0, NULL); + /* We handle the special case of the output lines */ + if (mc_global.tty.console_flag != '\0' && output_lines != 0) + { + unsigned char end_line; + + end_line = LINES - (mc_global.keybar_visible ? 1 : 0) - 1; + show_console_contents (output_start_y, end_line - output_lines, end_line); + } + return MSG_HANDLED; + + case MSG_RESIZE: + widget_adjust_position (w->pos_flags, &w->rect); + setup_panels (); + menubar_arrange (the_menubar); + return MSG_HANDLED; + + case MSG_IDLE: + /* We only need the first idle event to show user menu after start */ + widget_idle (w, FALSE); + + if (boot_current_is_left) + widget_select (get_panel_widget (0)); + else + widget_select (get_panel_widget (1)); + + if (auto_menu) + midnight_execute_cmd (NULL, CK_UserMenu); + return MSG_HANDLED; + + case MSG_KEY: + if (w->ext_mode) + { + command = widget_lookup_key (w, parm); + if (command != CK_IgnoreKey) + return midnight_execute_cmd (NULL, command); + } + + /* FIXME: should handle all menu shortcuts before this point */ + if (widget_get_state (WIDGET (the_menubar), WST_FOCUSED)) + return MSG_NOT_HANDLED; + + if (parm == '\n' && !is_cmdline_mute ()) + { + if (handle_cmdline_enter ()) + return MSG_HANDLED; + /* Else: the panel will handle it. */ + } + + if ((!mc_global.tty.alternate_plus_minus + || !(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)) && !quote + && !current_panel->quick_search.active) + { + if (!only_leading_plus_minus) + { + /* Special treatment, since the input line will eat them */ + if (parm == '+') + return send_message (current_panel, filemanager, MSG_ACTION, CK_Select, NULL); + + if (parm == '\\' || parm == '-') + return send_message (current_panel, filemanager, MSG_ACTION, CK_Unselect, NULL); + + if (parm == '*') + return send_message (current_panel, filemanager, MSG_ACTION, CK_SelectInvert, + NULL); + } + else if (!command_prompt || input_is_empty (cmdline)) + { + /* Special treatment '+', '-', '\', '*' only when this is + * first char on input line + */ + if (parm == '+') + return send_message (current_panel, filemanager, MSG_ACTION, CK_Select, NULL); + + if (parm == '\\' || parm == '-') + return send_message (current_panel, filemanager, MSG_ACTION, CK_Unselect, NULL); + + if (parm == '*') + return send_message (current_panel, filemanager, MSG_ACTION, CK_SelectInvert, + NULL); + } + } + return MSG_NOT_HANDLED; + + case MSG_HOTKEY_HANDLED: + if ((get_current_type () == view_listing) && current_panel->quick_search.active) + { + current_panel->dirty = TRUE; /* FIXME: unneeded? */ + send_message (current_panel, NULL, MSG_ACTION, CK_SearchStop, NULL); + } + return MSG_HANDLED; + + case MSG_UNHANDLED_KEY: + { + cb_ret_t v = MSG_NOT_HANDLED; + + command = widget_lookup_key (w, parm); + if (command != CK_IgnoreKey) + v = midnight_execute_cmd (NULL, command); + + if (v == MSG_NOT_HANDLED && command_prompt && !is_cmdline_mute ()) + v = send_message (cmdline, NULL, MSG_KEY, parm, NULL); + + return v; + } + + case MSG_POST_KEY: + if (!widget_get_state (WIDGET (the_menubar), WST_FOCUSED)) + update_dirty_panels (); + return MSG_HANDLED; + + case MSG_ACTION: + /* Handle shortcuts, menu, and buttonbar. */ + return midnight_execute_cmd (sender, parm); + + case MSG_DESTROY: + panel_deinit (); + return MSG_HANDLED; + + default: + return dlg_default_callback (w, sender, msg, parm, data); + } +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +void +update_menu (void) +{ + menu_set_name (left_menu, panels_layout.horizontal_split ? _("&Above") : _("&Left")); + menu_set_name (right_menu, panels_layout.horizontal_split ? _("&Below") : _("&Right")); + menubar_arrange (the_menubar); + widget_set_visibility (WIDGET (the_menubar), menubar_visible); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +midnight_set_buttonbar (WButtonBar * b) +{ + Widget *w = WIDGET (filemanager); + + buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), w->keymap, NULL); + buttonbar_set_label (b, 2, Q_ ("ButtonBar|Menu"), w->keymap, NULL); + buttonbar_set_label (b, 3, Q_ ("ButtonBar|View"), w->keymap, NULL); + buttonbar_set_label (b, 4, Q_ ("ButtonBar|Edit"), w->keymap, NULL); + buttonbar_set_label (b, 5, Q_ ("ButtonBar|Copy"), w->keymap, NULL); + buttonbar_set_label (b, 6, Q_ ("ButtonBar|RenMov"), w->keymap, NULL); + buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), w->keymap, NULL); + buttonbar_set_label (b, 8, Q_ ("ButtonBar|Delete"), w->keymap, NULL); + buttonbar_set_label (b, 9, Q_ ("ButtonBar|PullDn"), w->keymap, NULL); + buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), w->keymap, NULL); +} + +/* --------------------------------------------------------------------------------------------- */ +/** + * Return a random hint. If force is TRUE, ignore the timeout. + */ + +char * +get_random_hint (gboolean force) +{ + static const gint64 update_period = 60 * G_USEC_PER_SEC; + static gint64 tv = 0; + + char *data, *result, *eop; + size_t len, start; + GIConv conv; + + /* Do not change hints more often than one minute */ + if (!force && !mc_time_elapsed (&tv, update_period)) + return g_strdup (""); + + data = load_mc_home_file (mc_global.share_data_dir, MC_HINT, NULL, &len); + if (data == NULL) + return NULL; + + /* get a random entry */ + srand ((unsigned int) (tv / G_USEC_PER_SEC)); + start = ((size_t) rand ()) % (len - 1); + + /* Search the start of paragraph */ + for (; start != 0; start--) + if (data[start] == '\n' && data[start + 1] == '\n') + { + start += 2; + break; + } + + /* Search the end of paragraph */ + for (eop = data + start; *eop != '\0'; eop++) + { + if (*eop == '\n' && *(eop + 1) == '\n') + { + *eop = '\0'; + break; + } + if (*eop == '\n') + *eop = ' '; + } + + /* hint files are stored in utf-8 */ + /* try convert hint file from utf-8 to terminal encoding */ + conv = str_crt_conv_from ("UTF-8"); + if (conv == INVALID_CONV) + result = g_strndup (data + start, len - start); + else + { + GString *buffer; + gboolean nok; + + buffer = g_string_sized_new (len - start); + nok = (str_convert (conv, data + start, buffer) == ESTR_FAILURE); + result = g_string_free (buffer, nok); + str_close_conv (conv); + } + + g_free (data); + return result; +} + + +/* --------------------------------------------------------------------------------------------- */ +/** + * Load new hint and display it. + * IF force is not 0, ignore the timeout. + */ + +void +load_hint (gboolean force) +{ + char *hint; + + if (WIDGET (the_hint)->owner == NULL) + return; + + if (!mc_global.message_visible) + { + label_set_text (the_hint, NULL); + return; + } + + hint = get_random_hint (force); + + if (hint != NULL) + { + if (*hint != '\0') + set_hintbar (hint); + g_free (hint); + } + else + { + char text[BUF_SMALL]; + + g_snprintf (text, sizeof (text), _("GNU Midnight Commander %s\n"), mc_global.mc_version); + set_hintbar (text); + } +} + +/* --------------------------------------------------------------------------------------------- */ +/** + * Change current panel in the file manager. + * + * @return current_panel + */ + +WPanel * +change_panel (void) +{ + input_complete_free (cmdline); + group_select_next_widget (GROUP (filemanager)); + return current_panel; +} + +/* --------------------------------------------------------------------------------------------- */ + +/** Save current stat of directories to avoid reloading the panels + * when no modifications have taken place + */ +void +save_cwds_stat (void) +{ + if (panels_options.fast_reload) + { + mc_stat (current_panel->cwd_vpath, &(current_panel->dir_stat)); + if (get_other_type () == view_listing) + mc_stat (other_panel->cwd_vpath, &(other_panel->dir_stat)); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +gboolean +quiet_quit_cmd (void) +{ + print_last_revert = TRUE; + return quit_cmd_internal (1); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** Run the main dialog that occupies the whole screen */ +gboolean +do_nc (void) +{ + gboolean ret; + +#ifdef USE_INTERNAL_EDIT + edit_stack_init (); +#endif + + filemanager = dlg_create (FALSE, 0, 0, 1, 1, WPOS_FULLSCREEN, FALSE, dialog_colors, + midnight_callback, NULL, "[main]", NULL); + + /* Check if we were invoked as an editor or file viewer */ + if (mc_global.mc_run_mode != MC_RUN_FULL) + { + setup_dummy_mc (); + ret = mc_maybe_editor_or_viewer (); + } + else + { + /* We only need the first idle event to show user menu after start */ + widget_idle (WIDGET (filemanager), TRUE); + + setup_mc (); + mc_filehighlight = mc_fhl_new (TRUE); + + create_file_manager (); + (void) dlg_run (filemanager); + + mc_fhl_free (&mc_filehighlight); + + ret = TRUE; + + /* widget_destroy destroys even current_panel->cwd_vpath, so we have to save a copy :) */ + if (mc_args__last_wd_file != NULL && vfs_current_is_local ()) + last_wd_string = g_strdup (vfs_path_as_str (current_panel->cwd_vpath)); + + /* don't handle VFS timestamps for dirs opened in panels */ + mc_event_destroy (MCEVENT_GROUP_CORE, "vfs_timestamp"); + } + + /* Program end */ + mc_global.midnight_shutdown = TRUE; + dialog_switch_shutdown (); + done_mc (); + widget_destroy (WIDGET (filemanager)); + current_panel = NULL; + +#ifdef USE_INTERNAL_EDIT + edit_stack_free (); +#endif + + if ((quit & SUBSHELL_EXIT) == 0) + tty_clear_screen (); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ -- cgit v1.2.3