root/src/filemanager/filemanager.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. stop_dialogs
  2. treebox_cmd
  3. listmode_cmd
  4. create_panel_menu
  5. create_file_menu
  6. create_command_menu
  7. create_options_menu
  8. init_menu
  9. menu_last_selected_cmd
  10. menu_cmd
  11. sort_cmd
  12. midnight_get_shortcut
  13. midnight_get_title
  14. toggle_panels_split
  15. check_panel_timestamp
  16. check_current_panel_timestamp
  17. check_other_panel_timestamp
  18. print_vfs_message
  19. create_panels
  20. midnight_put_panel_path
  21. put_link
  22. put_current_link
  23. put_other_link
  24. put_current_selected
  25. put_tagged
  26. put_current_tagged
  27. put_other_tagged
  28. setup_mc
  29. setup_dummy_mc
  30. done_mc
  31. create_file_manager
  32. prepend_cwd_on_local
  33. mc_maybe_editor_or_viewer
  34. show_editor_viewer_history
  35. quit_cmd_internal
  36. quit_cmd
  37. update_dirty_panels
  38. toggle_show_hidden
  39. midnight_execute_cmd
  40. is_cmdline_mute
  41. handle_cmdline_enter
  42. midnight_callback
  43. update_menu
  44. midnight_set_buttonbar
  45. get_random_hint
  46. load_hint
  47. change_panel
  48. save_cwds_stat
  49. quiet_quit_cmd
  50. do_nc

   1 /*
   2    Main dialog (file panels) of the Midnight Commander
   3 
   4    Copyright (C) 1994-2021
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Miguel de Icaza, 1994, 1995, 1996, 1997
   9    Janne Kukonlehto, 1994, 1995
  10    Norbert Warmuth, 1997
  11    Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2012, 2013, 2020
  12    Slava Zanko <slavazanko@gmail.com>, 2013
  13 
  14    This file is part of the Midnight Commander.
  15 
  16    The Midnight Commander is free software: you can redistribute it
  17    and/or modify it under the terms of the GNU General Public License as
  18    published by the Free Software Foundation, either version 3 of the License,
  19    or (at your option) any later version.
  20 
  21    The Midnight Commander is distributed in the hope that it will be useful,
  22    but WITHOUT ANY WARRANTY; without even the implied warranty of
  23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24    GNU General Public License for more details.
  25 
  26    You should have received a copy of the GNU General Public License
  27    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  28  */
  29 
  30 /** \file filemanager.c
  31  *  \brief Source: main dialog (file panels) of the Midnight Commander
  32  */
  33 
  34 #include <config.h>
  35 
  36 #include <ctype.h>
  37 #include <errno.h>
  38 #include <locale.h>
  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 #include <string.h>
  42 #include <sys/types.h>
  43 #include <sys/stat.h>
  44 #include <sys/wait.h>
  45 #include <pwd.h>                /* for username in xterm title */
  46 
  47 #include "lib/global.h"
  48 #include "lib/fileloc.h"        /* MC_HINT */
  49 
  50 #include "lib/tty/tty.h"
  51 #include "lib/tty/key.h"        /* KEY_M_* masks */
  52 #include "lib/skin.h"
  53 #include "lib/util.h"
  54 
  55 #include "lib/vfs/vfs.h"
  56 
  57 #include "src/args.h"
  58 #ifdef ENABLE_SUBSHELL
  59 #include "src/subshell/subshell.h"
  60 #endif
  61 #include "src/execute.h"        /* toggle_subshell */
  62 #include "src/setup.h"          /* variables */
  63 #include "src/learn.h"          /* learn_keys() */
  64 #include "src/keymap.h"
  65 #include "lib/fileloc.h"        /* MC_FILEPOS_FILE */
  66 #include "lib/keybind.h"
  67 #include "lib/event.h"
  68 
  69 #include "tree.h"
  70 #include "boxes.h"              /* sort_box(), tree_box() */
  71 #include "layout.h"
  72 #include "cmd.h"                /* commands */
  73 #include "hotlist.h"
  74 #include "panelize.h"
  75 #include "command.h"            /* cmdline */
  76 #include "dir.h"                /* dir_list_clean() */
  77 
  78 #ifdef USE_INTERNAL_EDIT
  79 #include "src/editor/edit.h"
  80 #endif
  81 
  82 #ifdef USE_DIFF_VIEW
  83 #include "src/diffviewer/ydiff.h"
  84 #endif
  85 
  86 #include "src/consaver/cons.saver.h"    /* show_console_contents */
  87 #include "src/file_history.h"   /* show_file_history() */
  88 
  89 #include "filemanager.h"
  90 
  91 /*** global variables ****************************************************************************/
  92 
  93 /* When the modes are active, left_panel, right_panel and tree_panel */
  94 /* point to a proper data structure.  You should check with the functions */
  95 /* get_current_type and get_other_type the types of the panels before using */
  96 /* this pointer variables */
  97 
  98 /* The structures for the panels */
  99 WPanel *left_panel = NULL;
 100 WPanel *right_panel = NULL;
 101 /* Pointer to the selected and unselected panel */
 102 WPanel *current_panel = NULL;
 103 
 104 /* The Menubar */
 105 WMenuBar *the_menubar = NULL;
 106 /* The widget where we draw the prompt */
 107 WLabel *the_prompt;
 108 /* The hint bar */
 109 WLabel *the_hint;
 110 /* The button bar */
 111 WButtonBar *the_bar;
 112 
 113 /* The prompt */
 114 const char *mc_prompt = NULL;
 115 
 116 /*** file scope macro definitions ****************************************************************/
 117 
 118 #ifdef HAVE_CHARSET
 119 /*
 120  * Don't restrict the output on the screen manager level,
 121  * the translation tables take care of it.
 122  */
 123 #endif /* !HAVE_CHARSET */
 124 
 125 /*** file scope type declarations ****************************************************************/
 126 
 127 /*** file scope variables ************************************************************************/
 128 
 129 static menu_t *left_menu, *right_menu;
 130 
 131 /*** file scope functions ************************************************************************/
 132 
 133 /** Stop MC main dialog and the current dialog if it exists.
 134   * Needed to provide fast exit from MC viewer or editor on shell exit */
 135 static void
 136 stop_dialogs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 137 {
 138     dlg_stop (filemanager);
 139 
 140     if (top_dlg != NULL)
 141         dlg_stop (DIALOG (top_dlg->data));
 142 }
 143 
 144 /* --------------------------------------------------------------------------------------------- */
 145 
 146 static void
 147 treebox_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 148 {
 149     char *sel_dir;
 150 
 151     sel_dir = tree_box (selection (current_panel)->fname->str);
 152     if (sel_dir != NULL)
 153     {
 154         vfs_path_t *sel_vdir;
 155 
 156         sel_vdir = vfs_path_from_str (sel_dir);
 157         panel_cd (current_panel, sel_vdir, cd_exact);
 158         vfs_path_free (sel_vdir, TRUE);
 159         g_free (sel_dir);
 160     }
 161 }
 162 
 163 /* --------------------------------------------------------------------------------------------- */
 164 
 165 #ifdef LISTMODE_EDITOR
 166 static void
 167 listmode_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 168 {
 169     char *newmode;
 170 
 171     if (get_current_type () != view_listing)
 172         return;
 173 
 174     newmode = listmode_edit (current_panel->user_format);
 175     if (!newmode)
 176         return;
 177 
 178     g_free (current_panel->user_format);
 179     current_panel->list_format = list_user;
 180     current_panel->user_format = newmode;
 181     set_panel_formats (current_panel);
 182 
 183     do_refresh ();
 184 }
 185 #endif /* LISTMODE_EDITOR */
 186 
 187 /* --------------------------------------------------------------------------------------------- */
 188 
 189 static GList *
 190 create_panel_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 191 {
 192     GList *entries = NULL;
 193 
 194     entries = g_list_prepend (entries, menu_entry_create (_("File listin&g"), CK_PanelListing));
 195     entries = g_list_prepend (entries, menu_entry_create (_("&Quick view"), CK_PanelQuickView));
 196     entries = g_list_prepend (entries, menu_entry_create (_("&Info"), CK_PanelInfo));
 197     entries = g_list_prepend (entries, menu_entry_create (_("&Tree"), CK_PanelTree));
 198     entries = g_list_prepend (entries, menu_separator_create ());
 199     entries =
 200         g_list_prepend (entries,
 201                         menu_entry_create (_("&Listing format..."), CK_SetupListingFormat));
 202     entries = g_list_prepend (entries, menu_entry_create (_("&Sort order..."), CK_Sort));
 203     entries = g_list_prepend (entries, menu_entry_create (_("&Filter..."), CK_Filter));
 204 #ifdef HAVE_CHARSET
 205     entries = g_list_prepend (entries, menu_entry_create (_("&Encoding..."), CK_SelectCodepage));
 206 #endif
 207     entries = g_list_prepend (entries, menu_separator_create ());
 208 #ifdef ENABLE_VFS_FTP
 209     entries = g_list_prepend (entries, menu_entry_create (_("FT&P link..."), CK_ConnectFtp));
 210 #endif
 211 #ifdef ENABLE_VFS_FISH
 212     entries = g_list_prepend (entries, menu_entry_create (_("S&hell link..."), CK_ConnectFish));
 213 #endif
 214 #ifdef ENABLE_VFS_SFTP
 215     entries = g_list_prepend (entries, menu_entry_create (_("S&FTP link..."), CK_ConnectSftp));
 216 #endif
 217     entries = g_list_prepend (entries, menu_entry_create (_("Paneli&ze"), CK_Panelize));
 218     entries = g_list_prepend (entries, menu_separator_create ());
 219     entries = g_list_prepend (entries, menu_entry_create (_("&Rescan"), CK_Reread));
 220 
 221     return g_list_reverse (entries);
 222 }
 223 
 224 /* --------------------------------------------------------------------------------------------- */
 225 
 226 static GList *
 227 create_file_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 228 {
 229     GList *entries = NULL;
 230 
 231     entries = g_list_prepend (entries, menu_entry_create (_("&View"), CK_View));
 232     entries = g_list_prepend (entries, menu_entry_create (_("Vie&w file..."), CK_ViewFile));
 233     entries = g_list_prepend (entries, menu_entry_create (_("&Filtered view"), CK_ViewFiltered));
 234     entries = g_list_prepend (entries, menu_entry_create (_("&Edit"), CK_Edit));
 235     entries = g_list_prepend (entries, menu_entry_create (_("&Copy"), CK_Copy));
 236     entries = g_list_prepend (entries, menu_entry_create (_("C&hmod"), CK_ChangeMode));
 237     entries = g_list_prepend (entries, menu_entry_create (_("&Link"), CK_Link));
 238     entries = g_list_prepend (entries, menu_entry_create (_("&Symlink"), CK_LinkSymbolic));
 239     entries =
 240         g_list_prepend (entries,
 241                         menu_entry_create (_("Relative symlin&k"), CK_LinkSymbolicRelative));
 242     entries = g_list_prepend (entries, menu_entry_create (_("Edit s&ymlink"), CK_LinkSymbolicEdit));
 243     entries = g_list_prepend (entries, menu_entry_create (_("Ch&own"), CK_ChangeOwn));
 244     entries =
 245         g_list_prepend (entries, menu_entry_create (_("&Advanced chown"), CK_ChangeOwnAdvanced));
 246 #ifdef ENABLE_EXT2FS_ATTR
 247     entries = g_list_prepend (entries, menu_entry_create (_("Cha&ttr"), CK_ChangeAttributes));
 248 #endif
 249     entries = g_list_prepend (entries, menu_entry_create (_("&Rename/Move"), CK_Move));
 250     entries = g_list_prepend (entries, menu_entry_create (_("&Mkdir"), CK_MakeDir));
 251     entries = g_list_prepend (entries, menu_entry_create (_("&Delete"), CK_Delete));
 252     entries = g_list_prepend (entries, menu_entry_create (_("&Quick cd"), CK_CdQuick));
 253     entries = g_list_prepend (entries, menu_separator_create ());
 254     entries = g_list_prepend (entries, menu_entry_create (_("Select &group"), CK_Select));
 255     entries = g_list_prepend (entries, menu_entry_create (_("U&nselect group"), CK_Unselect));
 256     entries = g_list_prepend (entries, menu_entry_create (_("&Invert selection"), CK_SelectInvert));
 257     entries = g_list_prepend (entries, menu_separator_create ());
 258     entries = g_list_prepend (entries, menu_entry_create (_("E&xit"), CK_Quit));
 259 
 260     return g_list_reverse (entries);
 261 }
 262 
 263 /* --------------------------------------------------------------------------------------------- */
 264 
 265 static GList *
 266 create_command_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 267 {
 268     /* I know, I'm lazy, but the tree widget when it's not running
 269      * as a panel still has some problems, I have not yet finished
 270      * the WTree widget port, sorry.
 271      */
 272     GList *entries = NULL;
 273 
 274     entries = g_list_prepend (entries, menu_entry_create (_("&User menu"), CK_UserMenu));
 275     entries = g_list_prepend (entries, menu_entry_create (_("&Directory tree"), CK_Tree));
 276     entries = g_list_prepend (entries, menu_entry_create (_("&Find file"), CK_Find));
 277     entries = g_list_prepend (entries, menu_entry_create (_("S&wap panels"), CK_Swap));
 278     entries = g_list_prepend (entries, menu_entry_create (_("Switch &panels on/off"), CK_Shell));
 279     entries =
 280         g_list_prepend (entries, menu_entry_create (_("&Compare directories"), CK_CompareDirs));
 281 #ifdef USE_DIFF_VIEW
 282     entries = g_list_prepend (entries, menu_entry_create (_("C&ompare files"), CK_CompareFiles));
 283 #endif
 284     entries =
 285         g_list_prepend (entries, menu_entry_create (_("E&xternal panelize"), CK_ExternalPanelize));
 286     entries = g_list_prepend (entries, menu_entry_create (_("Show directory s&izes"), CK_DirSize));
 287     entries = g_list_prepend (entries, menu_separator_create ());
 288     entries = g_list_prepend (entries, menu_entry_create (_("Command &history"), CK_History));
 289     entries =
 290         g_list_prepend (entries,
 291                         menu_entry_create (_("Viewed/edited files hi&story"),
 292                                            CK_EditorViewerHistory));
 293     entries = g_list_prepend (entries, menu_entry_create (_("Di&rectory hotlist"), CK_HotList));
 294 #ifdef ENABLE_VFS
 295     entries = g_list_prepend (entries, menu_entry_create (_("&Active VFS list"), CK_VfsList));
 296 #endif
 297 #ifdef ENABLE_BACKGROUND
 298     entries = g_list_prepend (entries, menu_entry_create (_("&Background jobs"), CK_Jobs));
 299 #endif
 300     entries = g_list_prepend (entries, menu_entry_create (_("Screen lis&t"), CK_ScreenList));
 301     entries = g_list_prepend (entries, menu_separator_create ());
 302 #ifdef ENABLE_VFS_UNDELFS
 303     entries =
 304         g_list_prepend (entries,
 305                         menu_entry_create (_("&Undelete files (ext2fs only)"), CK_Undelete));
 306 #endif
 307 #ifdef LISTMODE_EDITOR
 308     entries = g_list_prepend (entries, menu_entry_create (_("&Listing format edit"), CK_ListMode));
 309 #endif
 310 #if defined (ENABLE_VFS_UNDELFS) || defined (LISTMODE_EDITOR)
 311     entries = g_list_prepend (entries, menu_separator_create ());
 312 #endif
 313     entries =
 314         g_list_prepend (entries,
 315                         menu_entry_create (_("Edit &extension file"), CK_EditExtensionsFile));
 316     entries = g_list_prepend (entries, menu_entry_create (_("Edit &menu file"), CK_EditUserMenu));
 317     entries =
 318         g_list_prepend (entries,
 319                         menu_entry_create (_("Edit hi&ghlighting group file"),
 320                                            CK_EditFileHighlightFile));
 321 
 322     return g_list_reverse (entries);
 323 }
 324 
 325 /* --------------------------------------------------------------------------------------------- */
 326 
 327 static GList *
 328 create_options_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 329 {
 330     GList *entries = NULL;
 331 
 332     entries = g_list_prepend (entries, menu_entry_create (_("&Configuration..."), CK_Options));
 333     entries = g_list_prepend (entries, menu_entry_create (_("&Layout..."), CK_OptionsLayout));
 334     entries = g_list_prepend (entries, menu_entry_create (_("&Panel options..."), CK_OptionsPanel));
 335     entries =
 336         g_list_prepend (entries, menu_entry_create (_("C&onfirmation..."), CK_OptionsConfirm));
 337     entries =
 338         g_list_prepend (entries, menu_entry_create (_("&Appearance..."), CK_OptionsAppearance));
 339     entries =
 340         g_list_prepend (entries, menu_entry_create (_("&Display bits..."), CK_OptionsDisplayBits));
 341     entries = g_list_prepend (entries, menu_entry_create (_("Learn &keys..."), CK_LearnKeys));
 342 #ifdef ENABLE_VFS
 343     entries = g_list_prepend (entries, menu_entry_create (_("&Virtual FS..."), CK_OptionsVfs));
 344 #endif
 345     entries = g_list_prepend (entries, menu_separator_create ());
 346     entries = g_list_prepend (entries, menu_entry_create (_("&Save setup"), CK_SaveSetup));
 347 
 348     return g_list_reverse (entries);
 349 }
 350 
 351 /* --------------------------------------------------------------------------------------------- */
 352 
 353 static void
 354 init_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 355 {
 356     left_menu = create_menu ("", create_panel_menu (), "[Left and Right Menus]");
 357     menubar_add_menu (the_menubar, left_menu);
 358     menubar_add_menu (the_menubar, create_menu (_("&File"), create_file_menu (), "[File Menu]"));
 359     menubar_add_menu (the_menubar,
 360                       create_menu (_("&Command"), create_command_menu (), "[Command Menu]"));
 361     menubar_add_menu (the_menubar,
 362                       create_menu (_("&Options"), create_options_menu (), "[Options Menu]"));
 363     right_menu = create_menu ("", create_panel_menu (), "[Left and Right Menus]");
 364     menubar_add_menu (the_menubar, right_menu);
 365     update_menu ();
 366 }
 367 
 368 /* --------------------------------------------------------------------------------------------- */
 369 
 370 static void
 371 menu_last_selected_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 372 {
 373     menubar_activate (the_menubar, drop_menus, -1);
 374 }
 375 
 376 /* --------------------------------------------------------------------------------------------- */
 377 
 378 static void
 379 menu_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 380 {
 381     int selected;
 382 
 383     if ((get_current_index () == 0) == current_panel->active)
 384         selected = 0;
 385     else
 386         selected = g_list_length (the_menubar->menu) - 1;
 387 
 388     menubar_activate (the_menubar, drop_menus, selected);
 389 }
 390 
 391 /* --------------------------------------------------------------------------------------------- */
 392 
 393 static void
 394 sort_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 395 {
 396     WPanel *p;
 397     const panel_field_t *sort_order;
 398 
 399     if (!SELECTED_IS_PANEL)
 400         return;
 401 
 402     p = MENU_PANEL;
 403     sort_order = sort_box (&p->sort_info, p->sort_field);
 404     panel_set_sort_order (p, sort_order);
 405 }
 406 
 407 /* --------------------------------------------------------------------------------------------- */
 408 
 409 static char *
 410 midnight_get_shortcut (long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 411 {
 412     const char *ext_map;
 413     const char *shortcut = NULL;
 414 
 415     shortcut = keybind_lookup_keymap_shortcut (filemanager_map, command);
 416     if (shortcut != NULL)
 417         return g_strdup (shortcut);
 418 
 419     shortcut = keybind_lookup_keymap_shortcut (panel_map, command);
 420     if (shortcut != NULL)
 421         return g_strdup (shortcut);
 422 
 423     ext_map = keybind_lookup_keymap_shortcut (filemanager_map, CK_ExtendedKeyMap);
 424     if (ext_map != NULL)
 425         shortcut = keybind_lookup_keymap_shortcut (filemanager_x_map, command);
 426     if (shortcut != NULL)
 427         return g_strdup_printf ("%s %s", ext_map, shortcut);
 428 
 429     return NULL;
 430 }
 431 
 432 /* --------------------------------------------------------------------------------------------- */
 433 
 434 static char *
 435 midnight_get_title (const WDialog * h, size_t len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 436 {
 437     char *path;
 438     char *login;
 439     char *p;
 440 
 441     (void) h;
 442 
 443     title_path_prepare (&path, &login);
 444 
 445     p = g_strdup_printf ("%s [%s]:%s", _("Panels:"), login, path);
 446     g_free (path);
 447     g_free (login);
 448     path = g_strdup (str_trunc (p, len - 4));
 449     g_free (p);
 450 
 451     return path;
 452 }
 453 
 454 /* --------------------------------------------------------------------------------------------- */
 455 
 456 static void
 457 toggle_panels_split (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 458 {
 459     panels_layout.horizontal_split = !panels_layout.horizontal_split;
 460     layout_change ();
 461     do_refresh ();
 462 }
 463 
 464 /* --------------------------------------------------------------------------------------------- */
 465 
 466 #ifdef ENABLE_VFS
 467 /* event helper */
 468 static gboolean
 469 check_panel_timestamp (const WPanel * panel, panel_view_mode_t mode, struct vfs_class *vclass,
     /* [previous][next][first][last][top][bottom][index][help]  */
 470                        vfsid id)
 471 {
 472     if (mode == view_listing)
 473     {
 474         const vfs_path_element_t *path_element;
 475 
 476         path_element = vfs_path_get_by_index (panel->cwd_vpath, -1);
 477 
 478         if (path_element->class != vclass)
 479             return FALSE;
 480 
 481         if (vfs_getid (panel->cwd_vpath) != id)
 482             return FALSE;
 483     }
 484     return TRUE;
 485 }
 486 
 487 /* --------------------------------------------------------------------------------------------- */
 488 
 489 /* event callback */
 490 static gboolean
 491 check_current_panel_timestamp (const gchar * event_group_name, const gchar * event_name,
     /* [previous][next][first][last][top][bottom][index][help]  */
 492                                gpointer init_data, gpointer data)
 493 {
 494     ev_vfs_stamp_create_t *event_data = (ev_vfs_stamp_create_t *) data;
 495 
 496     (void) event_group_name;
 497     (void) event_name;
 498     (void) init_data;
 499 
 500     event_data->ret =
 501         check_panel_timestamp (current_panel, get_current_type (), event_data->vclass,
 502                                event_data->id);
 503     return !event_data->ret;
 504 }
 505 
 506 /* --------------------------------------------------------------------------------------------- */
 507 
 508 /* event callback */
 509 static gboolean
 510 check_other_panel_timestamp (const gchar * event_group_name, const gchar * event_name,
     /* [previous][next][first][last][top][bottom][index][help]  */
 511                              gpointer init_data, gpointer data)
 512 {
 513     ev_vfs_stamp_create_t *event_data = (ev_vfs_stamp_create_t *) data;
 514 
 515     (void) event_group_name;
 516     (void) event_name;
 517     (void) init_data;
 518 
 519     event_data->ret =
 520         check_panel_timestamp (other_panel, get_other_type (), event_data->vclass, event_data->id);
 521     return !event_data->ret;
 522 }
 523 #endif /* ENABLE_VFS */
 524 
 525 /* --------------------------------------------------------------------------------------------- */
 526 
 527 /* event callback */
 528 static gboolean
 529 print_vfs_message (const gchar * event_group_name, const gchar * event_name,
     /* [previous][next][first][last][top][bottom][index][help]  */
 530                    gpointer init_data, gpointer data)
 531 {
 532     ev_vfs_print_message_t *event_data = (ev_vfs_print_message_t *) data;
 533 
 534     (void) event_group_name;
 535     (void) event_name;
 536     (void) init_data;
 537 
 538     if (mc_global.midnight_shutdown)
 539         goto ret;
 540 
 541     if (!mc_global.message_visible || the_hint == NULL || WIDGET (the_hint)->owner == NULL)
 542     {
 543         int col, row;
 544 
 545         if (!nice_rotating_dash || (ok_to_refresh <= 0))
 546             goto ret;
 547 
 548         /* Preserve current cursor position */
 549         tty_getyx (&row, &col);
 550 
 551         tty_gotoyx (0, 0);
 552         tty_setcolor (NORMAL_COLOR);
 553         tty_print_string (str_fit_to_term (event_data->msg, COLS - 1, J_LEFT));
 554 
 555         /* Restore cursor position */
 556         tty_gotoyx (row, col);
 557         mc_refresh ();
 558         goto ret;
 559     }
 560 
 561     if (mc_global.message_visible)
 562         set_hintbar (event_data->msg);
 563 
 564   ret:
 565     MC_PTR_FREE (event_data->msg);
 566     return TRUE;
 567 }
 568 
 569 /* --------------------------------------------------------------------------------------------- */
 570 
 571 static void
 572 create_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 573 {
 574     int current_index, other_index;
 575     panel_view_mode_t current_mode, other_mode;
 576     char *current_dir, *other_dir;
 577     vfs_path_t *original_dir;
 578 
 579     /*
 580      * Following cases from command line are possible:
 581      * 'mc' (no arguments):            mc_run_param0 == NULL, mc_run_param1 == NULL
 582      *                                 active panel uses current directory
 583      *                                 passive panel uses "other_dir" from panels.ini
 584      *
 585      * 'mc dir1 dir2' (two arguments): mc_run_param0 != NULL, mc_run_param1 != NULL
 586      *                                 active panel uses mc_run_param0
 587      *                                 passive panel uses mc_run_param1
 588      *
 589      * 'mc dir1' (single argument):    mc_run_param0 != NULL, mc_run_param1 == NULL
 590      *                                 active panel uses mc_run_param0
 591      *                                 passive panel uses "other_dir" from panels.ini
 592      */
 593 
 594     /* Set up panel directories */
 595     if (boot_current_is_left)
 596     {
 597         /* left panel is active */
 598         current_index = 0;
 599         other_index = 1;
 600         current_mode = startup_left_mode;
 601         other_mode = startup_right_mode;
 602 
 603         if (mc_run_param0 == NULL && mc_run_param1 == NULL)
 604         {
 605             /* no arguments */
 606             current_dir = NULL; /* assume current dir */
 607             other_dir = saved_other_dir;        /* from ini */
 608         }
 609         else if (mc_run_param0 != NULL && mc_run_param1 != NULL)
 610         {
 611             /* two arguments */
 612             current_dir = (char *) mc_run_param0;
 613             other_dir = mc_run_param1;
 614         }
 615         else                    /* mc_run_param0 != NULL && mc_run_param1 == NULL */
 616         {
 617             /* one argument */
 618             current_dir = (char *) mc_run_param0;
 619             other_dir = saved_other_dir;        /* from ini */
 620         }
 621     }
 622     else
 623     {
 624         /* right panel is active */
 625         current_index = 1;
 626         other_index = 0;
 627         current_mode = startup_right_mode;
 628         other_mode = startup_left_mode;
 629 
 630         if (mc_run_param0 == NULL && mc_run_param1 == NULL)
 631         {
 632             /* no arguments */
 633             current_dir = NULL; /* assume current dir */
 634             other_dir = saved_other_dir;        /* from ini */
 635         }
 636         else if (mc_run_param0 != NULL && mc_run_param1 != NULL)
 637         {
 638             /* two arguments */
 639             current_dir = (char *) mc_run_param0;
 640             other_dir = mc_run_param1;
 641         }
 642         else                    /* mc_run_param0 != NULL && mc_run_param1 == NULL */
 643         {
 644             /* one argument */
 645             current_dir = (char *) mc_run_param0;
 646             other_dir = saved_other_dir;        /* from ini */
 647         }
 648     }
 649 
 650     /* 1. Get current dir */
 651     original_dir = vfs_path_clone (vfs_get_raw_current_dir ());
 652 
 653     /* 2. Create passive panel */
 654     if (other_dir != NULL)
 655     {
 656         vfs_path_t *vpath;
 657 
 658         if (g_path_is_absolute (other_dir))
 659             vpath = vfs_path_from_str (other_dir);
 660         else
 661             vpath = vfs_path_append_new (original_dir, other_dir, (char *) NULL);
 662         mc_chdir (vpath);
 663         vfs_path_free (vpath, TRUE);
 664     }
 665     create_panel (other_index, other_mode);
 666 
 667     /* 3. Create active panel */
 668     if (current_dir == NULL)
 669         mc_chdir (original_dir);
 670     else
 671     {
 672         vfs_path_t *vpath;
 673 
 674         if (g_path_is_absolute (current_dir))
 675             vpath = vfs_path_from_str (current_dir);
 676         else
 677             vpath = vfs_path_append_new (original_dir, current_dir, (char *) NULL);
 678         mc_chdir (vpath);
 679         vfs_path_free (vpath, TRUE);
 680     }
 681     create_panel (current_index, current_mode);
 682 
 683     if (startup_left_mode == view_listing)
 684         current_panel = left_panel;
 685     else if (right_panel != NULL)
 686         current_panel = right_panel;
 687     else
 688         current_panel = left_panel;
 689 
 690     vfs_path_free (original_dir, TRUE);
 691 
 692 #ifdef ENABLE_VFS
 693     mc_event_add (MCEVENT_GROUP_CORE, "vfs_timestamp", check_other_panel_timestamp, NULL, NULL);
 694     mc_event_add (MCEVENT_GROUP_CORE, "vfs_timestamp", check_current_panel_timestamp, NULL, NULL);
 695 #endif /* ENABLE_VFS */
 696 
 697     mc_event_add (MCEVENT_GROUP_CORE, "vfs_print_message", print_vfs_message, NULL, NULL);
 698 }
 699 
 700 /* --------------------------------------------------------------------------------------------- */
 701 
 702 static void
 703 midnight_put_panel_path (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 704 {
 705     vfs_path_t *cwd_vpath;
 706     const char *cwd_vpath_str;
 707 
 708     if (!command_prompt)
 709         return;
 710 
 711 #ifdef HAVE_CHARSET
 712     cwd_vpath = remove_encoding_from_path (panel->cwd_vpath);
 713 #else
 714     cwd_vpath = vfs_path_clone (panel->cwd_vpath);
 715 #endif
 716 
 717     cwd_vpath_str = vfs_path_as_str (cwd_vpath);
 718 
 719     command_insert (cmdline, cwd_vpath_str, FALSE);
 720 
 721     if (!IS_PATH_SEP (cwd_vpath_str[strlen (cwd_vpath_str) - 1]))
 722         command_insert (cmdline, PATH_SEP_STR, FALSE);
 723 
 724     vfs_path_free (cwd_vpath, TRUE);
 725 }
 726 
 727 /* --------------------------------------------------------------------------------------------- */
 728 
 729 static void
 730 put_link (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 731 {
 732     if (!command_prompt)
 733         return;
 734     if (S_ISLNK (selection (panel)->st.st_mode))
 735     {
 736         char buffer[MC_MAXPATHLEN];
 737         vfs_path_t *vpath;
 738         int i;
 739 
 740         vpath =
 741             vfs_path_append_new (panel->cwd_vpath, selection (panel)->fname->str, (char *) NULL);
 742         i = mc_readlink (vpath, buffer, sizeof (buffer) - 1);
 743         vfs_path_free (vpath, TRUE);
 744 
 745         if (i > 0)
 746         {
 747             buffer[i] = '\0';
 748             command_insert (cmdline, buffer, TRUE);
 749         }
 750     }
 751 }
 752 
 753 /* --------------------------------------------------------------------------------------------- */
 754 
 755 static void
 756 put_current_link (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 757 {
 758     put_link (current_panel);
 759 }
 760 
 761 /* --------------------------------------------------------------------------------------------- */
 762 
 763 static void
 764 put_other_link (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 765 {
 766     if (get_other_type () == view_listing)
 767         put_link (other_panel);
 768 }
 769 
 770 /* --------------------------------------------------------------------------------------------- */
 771 
 772 /** Insert the selected file name into the input line */
 773 static void
 774 put_current_selected (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 775 {
 776     const char *tmp;
 777 
 778     if (!command_prompt)
 779         return;
 780 
 781     if (get_current_type () == view_tree)
 782     {
 783         WTree *tree;
 784         const vfs_path_t *selected_name;
 785 
 786         tree = (WTree *) get_panel_widget (get_current_index ());
 787         selected_name = tree_selected_name (tree);
 788         tmp = vfs_path_as_str (selected_name);
 789     }
 790     else
 791         tmp = selection (current_panel)->fname->str;
 792 
 793     command_insert (cmdline, tmp, TRUE);
 794 }
 795 
 796 /* --------------------------------------------------------------------------------------------- */
 797 
 798 static void
 799 put_tagged (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 800 {
 801     if (!command_prompt)
 802         return;
 803     input_disable_update (cmdline);
 804     if (panel->marked)
 805     {
 806         int i;
 807 
 808         for (i = 0; i < panel->dir.len; i++)
 809         {
 810             if (panel->dir.list[i].f.marked)
 811                 command_insert (cmdline, panel->dir.list[i].fname->str, TRUE);
 812         }
 813     }
 814     else
 815     {
 816         command_insert (cmdline, panel->dir.list[panel->selected].fname->str, TRUE);
 817     }
 818     input_enable_update (cmdline);
 819 }
 820 
 821 /* --------------------------------------------------------------------------------------------- */
 822 
 823 static void
 824 put_current_tagged (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 825 {
 826     put_tagged (current_panel);
 827 }
 828 
 829 /* --------------------------------------------------------------------------------------------- */
 830 
 831 static void
 832 put_other_tagged (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 833 {
 834     if (get_other_type () == view_listing)
 835         put_tagged (other_panel);
 836 }
 837 
 838 /* --------------------------------------------------------------------------------------------- */
 839 
 840 static void
 841 setup_mc (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 842 {
 843 #ifdef HAVE_SLANG
 844 #ifdef HAVE_CHARSET
 845     tty_display_8bit (TRUE);
 846 #else
 847     tty_display_8bit (mc_global.full_eight_bits);
 848 #endif /* HAVE_CHARSET */
 849 
 850 #else /* HAVE_SLANG */
 851 
 852 #ifdef HAVE_CHARSET
 853     tty_display_8bit (TRUE);
 854 #else
 855     tty_display_8bit (mc_global.eight_bit_clean);
 856 #endif /* HAVE_CHARSET */
 857 #endif /* HAVE_SLANG */
 858 
 859     if ((tty_baudrate () < 9600) || mc_global.tty.slow_terminal)
 860         verbose = FALSE;
 861 }
 862 
 863 /* --------------------------------------------------------------------------------------------- */
 864 
 865 static void
 866 setup_dummy_mc (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 867 {
 868     vfs_path_t *vpath;
 869     char *d;
 870     int ret;
 871 
 872     d = _vfs_get_cwd ();
 873     setup_mc ();
 874     vpath = vfs_path_from_str (d);
 875     ret = mc_chdir (vpath);
 876     (void) ret;
 877     vfs_path_free (vpath, TRUE);
 878     g_free (d);
 879 }
 880 
 881 /* --------------------------------------------------------------------------------------------- */
 882 
 883 static void
 884 done_mc (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 885 {
 886     /* Setup shutdown
 887      *
 888      * We sync the profiles since the hotlist may have changed, while
 889      * we only change the setup data if we have the auto save feature set
 890      */
 891 
 892     save_setup (auto_save_setup, panels_options.auto_save_setup);
 893 
 894     vfs_stamp_path (vfs_get_raw_current_dir ());
 895 }
 896 
 897 /* --------------------------------------------------------------------------------------------- */
 898 
 899 static void
 900 create_file_manager (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 901 {
 902     Widget *w = WIDGET (filemanager);
 903     WGroup *g = GROUP (filemanager);
 904 
 905     w->keymap = filemanager_map;
 906     w->ext_keymap = filemanager_x_map;
 907 
 908     filemanager->get_shortcut = midnight_get_shortcut;
 909     filemanager->get_title = midnight_get_title;
 910     /* allow rebind tab */
 911     widget_want_tab (w, TRUE);
 912 
 913     the_menubar = menubar_new (NULL);
 914     group_add_widget (g, the_menubar);
 915     init_menu ();
 916 
 917     create_panels ();
 918     group_add_widget (g, get_panel_widget (0));
 919     group_add_widget (g, get_panel_widget (1));
 920 
 921     the_hint = label_new (0, 0, 0);
 922     the_hint->transparent = TRUE;
 923     the_hint->auto_adjust_cols = 0;
 924     WIDGET (the_hint)->cols = COLS;
 925     group_add_widget (g, the_hint);
 926 
 927     cmdline = command_new (0, 0, 0);
 928     group_add_widget (g, cmdline);
 929 
 930     the_prompt = label_new (0, 0, mc_prompt);
 931     the_prompt->transparent = TRUE;
 932     group_add_widget (g, the_prompt);
 933 
 934     the_bar = buttonbar_new ();
 935     group_add_widget (g, the_bar);
 936     midnight_set_buttonbar (the_bar);
 937 
 938 #ifdef ENABLE_SUBSHELL
 939     /* Must be done after creation of cmdline and promt widgets to avoid potential
 940        NULL dereference in load_prompt() -> ... -> setup_cmdline() -> label_set_text(). */
 941     if (mc_global.tty.use_subshell)
 942         add_select_channel (mc_global.tty.subshell_pty, load_prompt, NULL);
 943 #endif /* !ENABLE_SUBSHELL */
 944 }
 945 
 946 /* --------------------------------------------------------------------------------------------- */
 947 
 948 /** result must be free'd (I think this should go in util.c) */
 949 static vfs_path_t *
 950 prepend_cwd_on_local (const char *filename)
     /* [previous][next][first][last][top][bottom][index][help]  */
 951 {
 952     vfs_path_t *vpath;
 953 
 954     vpath = vfs_path_from_str (filename);
 955     if (!vfs_file_is_local (vpath) || g_path_is_absolute (filename))
 956         return vpath;
 957 
 958     vfs_path_free (vpath, TRUE);
 959 
 960     return vfs_path_append_new (vfs_get_raw_current_dir (), filename, (char *) NULL);
 961 }
 962 
 963 /* --------------------------------------------------------------------------------------------- */
 964 
 965 /** Invoke the internal view/edit routine with:
 966  * the default processing and forcing the internal viewer/editor
 967  */
 968 static gboolean
 969 mc_maybe_editor_or_viewer (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 970 {
 971     gboolean ret;
 972 
 973     switch (mc_global.mc_run_mode)
 974     {
 975 #ifdef USE_INTERNAL_EDIT
 976     case MC_RUN_EDITOR:
 977         ret = edit_files ((GList *) mc_run_param0);
 978         break;
 979 #endif /* USE_INTERNAL_EDIT */
 980     case MC_RUN_VIEWER:
 981         {
 982             vfs_path_t *vpath = NULL;
 983 
 984             if (mc_run_param0 != NULL && *(char *) mc_run_param0 != '\0')
 985                 vpath = prepend_cwd_on_local ((char *) mc_run_param0);
 986 
 987             ret = view_file (vpath, FALSE, TRUE);
 988             vfs_path_free (vpath, TRUE);
 989             break;
 990         }
 991 #ifdef USE_DIFF_VIEW
 992     case MC_RUN_DIFFVIEWER:
 993         ret = dview_diff_cmd (mc_run_param0, mc_run_param1);
 994         break;
 995 #endif /* USE_DIFF_VIEW */
 996     default:
 997         ret = FALSE;
 998     }
 999 
1000     return ret;
1001 }
1002 
1003 /* --------------------------------------------------------------------------------------------- */
1004 
1005 static void
1006 show_editor_viewer_history (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1007 {
1008     char *s;
1009     int act;
1010 
1011     s = show_file_history (WIDGET (filemanager), &act);
1012     if (s != NULL)
1013     {
1014         vfs_path_t *s_vpath;
1015 
1016         switch (act)
1017         {
1018         case CK_Edit:
1019             s_vpath = vfs_path_from_str (s);
1020             edit_file_at_line (s_vpath, use_internal_edit, 0);
1021             break;
1022 
1023         case CK_View:
1024             s_vpath = vfs_path_from_str (s);
1025             view_file (s_vpath, use_internal_view, FALSE);
1026             break;
1027 
1028         default:
1029             {
1030                 char *d;
1031 
1032                 d = g_path_get_dirname (s);
1033                 s_vpath = vfs_path_from_str (d);
1034                 panel_cd (current_panel, s_vpath, cd_exact);
1035                 try_to_select (current_panel, s);
1036                 g_free (d);
1037             }
1038         }
1039 
1040         g_free (s);
1041         vfs_path_free (s_vpath, TRUE);
1042     }
1043 }
1044 
1045 /* --------------------------------------------------------------------------------------------- */
1046 
1047 static gboolean
1048 quit_cmd_internal (int quiet)
     /* [previous][next][first][last][top][bottom][index][help]  */
1049 {
1050     int q = quit;
1051     size_t n;
1052 
1053     n = dialog_switch_num () - 1;
1054     if (n != 0)
1055     {
1056         char msg[BUF_MEDIUM];
1057 
1058         g_snprintf (msg, sizeof (msg),
1059                     ngettext ("You have %zu opened screen. Quit anyway?",
1060                               "You have %zu opened screens. Quit anyway?", n), n);
1061 
1062         if (query_dialog (_("The Midnight Commander"), msg, D_NORMAL, 2, _("&Yes"), _("&No")) != 0)
1063             return FALSE;
1064         q = 1;
1065     }
1066     else if (quiet || !confirm_exit)
1067         q = 1;
1068     else if (query_dialog (_("The Midnight Commander"),
1069                            _("Do you really want to quit the Midnight Commander?"),
1070                            D_NORMAL, 2, _("&Yes"), _("&No")) == 0)
1071         q = 1;
1072 
1073     if (q != 0)
1074     {
1075 #ifdef ENABLE_SUBSHELL
1076         if (!mc_global.tty.use_subshell)
1077             stop_dialogs ();
1078         else if ((q = exit_subshell ()? 1 : 0) != 0)
1079 #endif
1080             stop_dialogs ();
1081     }
1082 
1083     if (q != 0)
1084         quit |= 1;
1085     return (quit != 0);
1086 }
1087 
1088 /* --------------------------------------------------------------------------------------------- */
1089 
1090 static gboolean
1091 quit_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1092 {
1093     return quit_cmd_internal (0);
1094 }
1095 
1096 /* --------------------------------------------------------------------------------------------- */
1097 
1098 /**
1099  * Repaint the contents of the panels without frames.  To schedule panel
1100  * for repainting, set panel->dirty to TRUE.  There are many reasons why
1101  * the panels need to be repainted, and this is a costly operation, so
1102  * it's done once per event.
1103  */
1104 
1105 static void
1106 update_dirty_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1107 {
1108     if (get_current_type () == view_listing && current_panel->dirty)
1109         widget_draw (WIDGET (current_panel));
1110 
1111     if (get_other_type () == view_listing && other_panel->dirty)
1112         widget_draw (WIDGET (other_panel));
1113 }
1114 
1115 /* --------------------------------------------------------------------------------------------- */
1116 
1117 static void
1118 toggle_show_hidden (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1119 {
1120     panels_options.show_dot_files = !panels_options.show_dot_files;
1121     update_panels (UP_RELOAD, UP_KEEPSEL);
1122     /* redraw panels forced */
1123     update_dirty_panels ();
1124 }
1125 
1126 /* --------------------------------------------------------------------------------------------- */
1127 
1128 static cb_ret_t
1129 midnight_execute_cmd (Widget * sender, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
1130 {
1131     cb_ret_t res = MSG_HANDLED;
1132 
1133     (void) sender;
1134 
1135     /* stop quick search before executing any command */
1136     send_message (current_panel, NULL, MSG_ACTION, CK_SearchStop, NULL);
1137 
1138     switch (command)
1139     {
1140     case CK_ChangePanel:
1141         (void) change_panel ();
1142         break;
1143     case CK_HotListAdd:
1144         add2hotlist_cmd (current_panel);
1145         break;
1146     case CK_SetupListingFormat:
1147         setup_listing_format_cmd ();
1148         break;
1149     case CK_ChangeMode:
1150         chmod_cmd (current_panel);
1151         break;
1152     case CK_ChangeOwn:
1153         chown_cmd (current_panel);
1154         break;
1155     case CK_ChangeOwnAdvanced:
1156         advanced_chown_cmd (current_panel);
1157         break;
1158 #ifdef ENABLE_EXT2FS_ATTR
1159     case CK_ChangeAttributes:
1160         chattr_cmd (current_panel);
1161         break;
1162 #endif
1163     case CK_CompareDirs:
1164         compare_dirs_cmd ();
1165         break;
1166     case CK_Options:
1167         configure_box ();
1168         break;
1169 #ifdef ENABLE_VFS
1170     case CK_OptionsVfs:
1171         configure_vfs_box ();
1172         break;
1173 #endif
1174     case CK_OptionsConfirm:
1175         confirm_box ();
1176         break;
1177     case CK_Copy:
1178         copy_cmd (current_panel);
1179         break;
1180     case CK_PutCurrentPath:
1181         midnight_put_panel_path (current_panel);
1182         break;
1183     case CK_PutCurrentSelected:
1184         put_current_selected ();
1185         break;
1186     case CK_PutCurrentFullSelected:
1187         midnight_put_panel_path (current_panel);
1188         put_current_selected ();
1189         break;
1190     case CK_PutCurrentLink:
1191         put_current_link ();
1192         break;
1193     case CK_PutCurrentTagged:
1194         put_current_tagged ();
1195         break;
1196     case CK_PutOtherPath:
1197         if (get_other_type () == view_listing)
1198             midnight_put_panel_path (other_panel);
1199         break;
1200     case CK_PutOtherLink:
1201         put_other_link ();
1202         break;
1203     case CK_PutOtherTagged:
1204         put_other_tagged ();
1205         break;
1206     case CK_Delete:
1207         delete_cmd (current_panel);
1208         break;
1209     case CK_ScreenList:
1210         dialog_switch_list ();
1211         break;
1212 #ifdef USE_DIFF_VIEW
1213     case CK_CompareFiles:
1214         diff_view_cmd ();
1215         break;
1216 #endif
1217     case CK_OptionsDisplayBits:
1218         display_bits_box ();
1219         break;
1220     case CK_Edit:
1221         edit_cmd (current_panel);
1222         break;
1223 #ifdef USE_INTERNAL_EDIT
1224     case CK_EditForceInternal:
1225         edit_cmd_force_internal (current_panel);
1226         break;
1227 #endif
1228     case CK_EditExtensionsFile:
1229         ext_cmd ();
1230         break;
1231     case CK_EditFileHighlightFile:
1232         edit_fhl_cmd ();
1233         break;
1234     case CK_EditUserMenu:
1235         edit_mc_menu_cmd ();
1236         break;
1237     case CK_LinkSymbolicEdit:
1238         edit_symlink_cmd ();
1239         break;
1240     case CK_ExternalPanelize:
1241         external_panelize ();
1242         break;
1243     case CK_Filter:
1244         filter_cmd ();
1245         break;
1246     case CK_ViewFiltered:
1247         view_filtered_cmd (current_panel);
1248         break;
1249     case CK_Find:
1250         find_cmd (current_panel);
1251         break;
1252 #ifdef ENABLE_VFS_FISH
1253     case CK_ConnectFish:
1254         fishlink_cmd ();
1255         break;
1256 #endif
1257 #ifdef ENABLE_VFS_FTP
1258     case CK_ConnectFtp:
1259         ftplink_cmd ();
1260         break;
1261 #endif
1262 #ifdef ENABLE_VFS_SFTP
1263     case CK_ConnectSftp:
1264         sftplink_cmd ();
1265         break;
1266 #endif
1267     case CK_Panelize:
1268         cd_panelize_cmd ();
1269         break;
1270     case CK_Help:
1271         help_cmd ();
1272         break;
1273     case CK_History:
1274         /* show the history of command line widget */
1275         send_message (cmdline, NULL, MSG_ACTION, CK_History, NULL);
1276         break;
1277     case CK_PanelInfo:
1278         if (sender == WIDGET (the_menubar))
1279             info_cmd ();        /* menu */
1280         else
1281             info_cmd_no_menu ();        /* shortcut or buttonbar */
1282         break;
1283 #ifdef ENABLE_BACKGROUND
1284     case CK_Jobs:
1285         jobs_box ();
1286         break;
1287 #endif
1288     case CK_OptionsLayout:
1289         layout_box ();
1290         break;
1291     case CK_OptionsAppearance:
1292         appearance_box ();
1293         break;
1294     case CK_LearnKeys:
1295         learn_keys ();
1296         break;
1297     case CK_Link:
1298         link_cmd (LINK_HARDLINK);
1299         break;
1300     case CK_PanelListing:
1301         listing_cmd ();
1302         break;
1303 #ifdef LISTMODE_EDITOR
1304     case CK_ListMode:
1305         listmode_cmd ();
1306         break;
1307 #endif
1308     case CK_Menu:
1309         menu_cmd ();
1310         break;
1311     case CK_MenuLastSelected:
1312         menu_last_selected_cmd ();
1313         break;
1314     case CK_MakeDir:
1315         mkdir_cmd (current_panel);
1316         break;
1317     case CK_OptionsPanel:
1318         panel_options_box ();
1319         break;
1320 #ifdef HAVE_CHARSET
1321     case CK_SelectCodepage:
1322         encoding_cmd ();
1323         break;
1324 #endif
1325     case CK_CdQuick:
1326         quick_cd_cmd (current_panel);
1327         break;
1328     case CK_HotList:
1329         hotlist_cmd (current_panel);
1330         break;
1331     case CK_PanelQuickView:
1332         if (sender == WIDGET (the_menubar))
1333             quick_view_cmd ();  /* menu */
1334         else
1335             quick_cmd_no_menu ();       /* shortcut or buttonabr */
1336         break;
1337     case CK_QuitQuiet:
1338         quiet_quit_cmd ();
1339         break;
1340     case CK_Quit:
1341         quit_cmd ();
1342         break;
1343     case CK_LinkSymbolicRelative:
1344         link_cmd (LINK_SYMLINK_RELATIVE);
1345         break;
1346     case CK_Move:
1347         rename_cmd (current_panel);
1348         break;
1349     case CK_Reread:
1350         reread_cmd ();
1351         break;
1352 #ifdef ENABLE_VFS
1353     case CK_VfsList:
1354         vfs_list (current_panel);
1355         break;
1356 #endif
1357     case CK_SaveSetup:
1358         save_setup_cmd ();
1359         break;
1360     case CK_Select:
1361     case CK_Unselect:
1362     case CK_SelectInvert:
1363         res = send_message (current_panel, filemanager, MSG_ACTION, command, NULL);
1364         break;
1365     case CK_Shell:
1366         toggle_subshell ();
1367         break;
1368     case CK_DirSize:
1369         smart_dirsize_cmd (current_panel);
1370         break;
1371     case CK_Sort:
1372         sort_cmd ();
1373         break;
1374     case CK_ExtendedKeyMap:
1375         WIDGET (filemanager)->ext_mode = TRUE;
1376         break;
1377     case CK_Suspend:
1378         mc_event_raise (MCEVENT_GROUP_CORE, "suspend", NULL);
1379         break;
1380     case CK_Swap:
1381         swap_cmd ();
1382         break;
1383     case CK_LinkSymbolic:
1384         link_cmd (LINK_SYMLINK_ABSOLUTE);
1385         break;
1386     case CK_ShowHidden:
1387         toggle_show_hidden ();
1388         break;
1389     case CK_SplitVertHoriz:
1390         toggle_panels_split ();
1391         break;
1392     case CK_SplitEqual:
1393         panels_split_equal ();
1394         break;
1395     case CK_SplitMore:
1396         panels_split_more ();
1397         break;
1398     case CK_SplitLess:
1399         panels_split_less ();
1400         break;
1401     case CK_PanelTree:
1402         panel_tree_cmd ();
1403         break;
1404     case CK_Tree:
1405         treebox_cmd ();
1406         break;
1407 #ifdef ENABLE_VFS_UNDELFS
1408     case CK_Undelete:
1409         undelete_cmd ();
1410         break;
1411 #endif
1412     case CK_UserMenu:
1413         user_file_menu_cmd ();
1414         break;
1415     case CK_View:
1416         view_cmd (current_panel);
1417         break;
1418     case CK_ViewFile:
1419         view_file_cmd (current_panel);
1420         break;
1421     case CK_EditorViewerHistory:
1422         show_editor_viewer_history ();
1423         break;
1424     case CK_Cancel:
1425         /* don't close panels due to SIGINT */
1426         break;
1427     default:
1428         res = MSG_NOT_HANDLED;
1429     }
1430 
1431     return res;
1432 }
1433 
1434 /* --------------------------------------------------------------------------------------------- */
1435 
1436 /**
1437  * Whether the command-line should not respond to key events.
1438  *
1439  * This is TRUE if a QuickView or TreeView have the focus, as they're going
1440  * to consume some keys and there's no sense in passing to the command-line
1441  * just the leftovers.
1442  */
1443 static gboolean
1444 is_cmdline_mute (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1445 {
1446     /* When one of panels is other than view_listing,
1447        current_panel points to view_listing panel all time independently of
1448        it's activity. Thus, we can't use get_current_type() here.
1449        current_panel should point to actualy current active panel
1450        independently of it's type. */
1451     return (!current_panel->active
1452             && (get_other_type () == view_quick || get_other_type () == view_tree));
1453 }
1454 
1455 /* --------------------------------------------------------------------------------------------- */
1456 
1457 /**
1458  * Handles the Enter key on the command-line.
1459  *
1460  * Returns TRUE if non-whitespace was indeed processed.
1461  */
1462 static gboolean
1463 handle_cmdline_enter (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1464 {
1465     size_t i;
1466 
1467     for (i = 0; cmdline->buffer[i] != '\0' && whitespace (cmdline->buffer[i]); i++)
1468         ;
1469 
1470     if (cmdline->buffer[i] != '\0')
1471     {
1472         send_message (cmdline, NULL, MSG_KEY, '\n', NULL);
1473         return TRUE;
1474     }
1475 
1476     input_insert (cmdline, "", FALSE);
1477     cmdline->point = 0;
1478 
1479     return FALSE;
1480 }
1481 
1482 /* --------------------------------------------------------------------------------------------- */
1483 
1484 static cb_ret_t
1485 midnight_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
1486 {
1487     long command;
1488 
1489     switch (msg)
1490     {
1491     case MSG_INIT:
1492         panel_init ();
1493         setup_panels ();
1494         return MSG_HANDLED;
1495 
1496     case MSG_DRAW:
1497         load_hint (TRUE);
1498         group_default_callback (w, NULL, MSG_DRAW, 0, NULL);
1499         /* We handle the special case of the output lines */
1500         if (mc_global.tty.console_flag != '\0' && output_lines != 0)
1501         {
1502             unsigned char end_line;
1503 
1504             end_line = LINES - (mc_global.keybar_visible ? 1 : 0) - 1;
1505             show_console_contents (output_start_y, end_line - output_lines, end_line);
1506         }
1507         return MSG_HANDLED;
1508 
1509     case MSG_RESIZE:
1510         widget_adjust_position (w->pos_flags, &w->y, &w->x, &w->lines, &w->cols);
1511         setup_panels ();
1512         menubar_arrange (the_menubar);
1513         return MSG_HANDLED;
1514 
1515     case MSG_IDLE:
1516         /* We only need the first idle event to show user menu after start */
1517         widget_idle (w, FALSE);
1518 
1519         if (boot_current_is_left)
1520             widget_select (get_panel_widget (0));
1521         else
1522             widget_select (get_panel_widget (1));
1523 
1524         if (auto_menu)
1525             midnight_execute_cmd (NULL, CK_UserMenu);
1526         return MSG_HANDLED;
1527 
1528     case MSG_KEY:
1529         if (w->ext_mode)
1530         {
1531             command = widget_lookup_key (w, parm);
1532             if (command != CK_IgnoreKey)
1533                 return midnight_execute_cmd (NULL, command);
1534         }
1535 
1536         /* FIXME: should handle all menu shortcuts before this point */
1537         if (widget_get_state (WIDGET (the_menubar), WST_FOCUSED))
1538             return MSG_NOT_HANDLED;
1539 
1540         if (parm == '\n' && !is_cmdline_mute ())
1541         {
1542             if (handle_cmdline_enter ())
1543                 return MSG_HANDLED;
1544             /* Else: the panel will handle it. */
1545         }
1546 
1547         if ((!mc_global.tty.alternate_plus_minus
1548              || !(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)) && !quote
1549             && !current_panel->quick_search.active)
1550         {
1551             if (!only_leading_plus_minus)
1552             {
1553                 /* Special treatement, since the input line will eat them */
1554                 if (parm == '+')
1555                     return send_message (current_panel, filemanager, MSG_ACTION, CK_Select, NULL);
1556 
1557                 if (parm == '\\' || parm == '-')
1558                     return send_message (current_panel, filemanager, MSG_ACTION, CK_Unselect, NULL);
1559 
1560                 if (parm == '*')
1561                     return send_message (current_panel, filemanager, MSG_ACTION, CK_SelectInvert,
1562                                          NULL);
1563             }
1564             else if (!command_prompt || input_is_empty (cmdline))
1565             {
1566                 /* Special treatement '+', '-', '\', '*' only when this is
1567                  * first char on input line
1568                  */
1569                 if (parm == '+')
1570                     return send_message (current_panel, filemanager, MSG_ACTION, CK_Select, NULL);
1571 
1572                 if (parm == '\\' || parm == '-')
1573                     return send_message (current_panel, filemanager, MSG_ACTION, CK_Unselect, NULL);
1574 
1575                 if (parm == '*')
1576                     return send_message (current_panel, filemanager, MSG_ACTION, CK_SelectInvert,
1577                                          NULL);
1578             }
1579         }
1580         return MSG_NOT_HANDLED;
1581 
1582     case MSG_HOTKEY_HANDLED:
1583         if ((get_current_type () == view_listing) && current_panel->quick_search.active)
1584         {
1585             current_panel->dirty = TRUE;        /* FIXME: unneeded? */
1586             send_message (current_panel, NULL, MSG_ACTION, CK_SearchStop, NULL);
1587         }
1588         return MSG_HANDLED;
1589 
1590     case MSG_UNHANDLED_KEY:
1591         {
1592             cb_ret_t v = MSG_NOT_HANDLED;
1593 
1594             command = widget_lookup_key (w, parm);
1595             if (command != CK_IgnoreKey)
1596                 v = midnight_execute_cmd (NULL, command);
1597 
1598             if (v == MSG_NOT_HANDLED && command_prompt && !is_cmdline_mute ())
1599                 v = send_message (cmdline, NULL, MSG_KEY, parm, NULL);
1600 
1601             return v;
1602         }
1603 
1604     case MSG_POST_KEY:
1605         if (!widget_get_state (WIDGET (the_menubar), WST_FOCUSED))
1606             update_dirty_panels ();
1607         return MSG_HANDLED;
1608 
1609     case MSG_ACTION:
1610         /* Handle shortcuts, menu, and buttonbar. */
1611         return midnight_execute_cmd (sender, parm);
1612 
1613     case MSG_DESTROY:
1614         panel_deinit ();
1615         return MSG_HANDLED;
1616 
1617     default:
1618         return dlg_default_callback (w, sender, msg, parm, data);
1619     }
1620 }
1621 
1622 /* --------------------------------------------------------------------------------------------- */
1623 /*** public functions ****************************************************************************/
1624 /* --------------------------------------------------------------------------------------------- */
1625 
1626 void
1627 update_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1628 {
1629     menu_set_name (left_menu, panels_layout.horizontal_split ? _("&Above") : _("&Left"));
1630     menu_set_name (right_menu, panels_layout.horizontal_split ? _("&Below") : _("&Right"));
1631     menubar_arrange (the_menubar);
1632     widget_set_visibility (WIDGET (the_menubar), menubar_visible);
1633 }
1634 
1635 /* --------------------------------------------------------------------------------------------- */
1636 
1637 void
1638 midnight_set_buttonbar (WButtonBar * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
1639 {
1640     Widget *w = WIDGET (filemanager);
1641 
1642     buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), w->keymap, NULL);
1643     buttonbar_set_label (b, 2, Q_ ("ButtonBar|Menu"), w->keymap, NULL);
1644     buttonbar_set_label (b, 3, Q_ ("ButtonBar|View"), w->keymap, NULL);
1645     buttonbar_set_label (b, 4, Q_ ("ButtonBar|Edit"), w->keymap, NULL);
1646     buttonbar_set_label (b, 5, Q_ ("ButtonBar|Copy"), w->keymap, NULL);
1647     buttonbar_set_label (b, 6, Q_ ("ButtonBar|RenMov"), w->keymap, NULL);
1648     buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), w->keymap, NULL);
1649     buttonbar_set_label (b, 8, Q_ ("ButtonBar|Delete"), w->keymap, NULL);
1650     buttonbar_set_label (b, 9, Q_ ("ButtonBar|PullDn"), w->keymap, NULL);
1651     buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), w->keymap, NULL);
1652 }
1653 
1654 /* --------------------------------------------------------------------------------------------- */
1655 /**
1656  * Return a random hint.  If force is TRUE, ignore the timeout.
1657  */
1658 
1659 char *
1660 get_random_hint (gboolean force)
     /* [previous][next][first][last][top][bottom][index][help]  */
1661 {
1662     static const gint64 update_period = 60 * G_USEC_PER_SEC;
1663     static gint64 tv = 0;
1664 
1665     char *data, *result = NULL, *eop;
1666     size_t len, start;
1667     GIConv conv;
1668 
1669     /* Do not change hints more often than one minute */
1670     if (!force && !mc_time_elapsed (&tv, update_period))
1671         return g_strdup ("");
1672 
1673     data = load_mc_home_file (mc_global.share_data_dir, MC_HINT, NULL, &len);
1674     if (data == NULL)
1675         return NULL;
1676 
1677     /* get a random entry */
1678     srand ((unsigned int) (tv / G_USEC_PER_SEC));
1679     start = ((size_t) rand ()) % (len - 1);
1680 
1681     /* Search the start of paragraph */
1682     for (; start != 0; start--)
1683         if (data[start] == '\n' && data[start + 1] == '\n')
1684         {
1685             start += 2;
1686             break;
1687         }
1688 
1689     /* Search the end of paragraph */
1690     for (eop = data + start; *eop != '\0'; eop++)
1691     {
1692         if (*eop == '\n' && *(eop + 1) == '\n')
1693         {
1694             *eop = '\0';
1695             break;
1696         }
1697         if (*eop == '\n')
1698             *eop = ' ';
1699     }
1700 
1701     /* hint files are stored in utf-8 */
1702     /* try convert hint file from utf-8 to terminal encoding */
1703     conv = str_crt_conv_from ("UTF-8");
1704     if (conv != INVALID_CONV)
1705     {
1706         GString *buffer;
1707 
1708         buffer = g_string_sized_new (len - start);
1709         if (str_convert (conv, &data[start], buffer) != ESTR_FAILURE)
1710             result = g_string_free (buffer, FALSE);
1711         else
1712             g_string_free (buffer, TRUE);
1713         str_close_conv (conv);
1714     }
1715     else
1716         result = g_strndup (data + start, len - start);
1717 
1718     g_free (data);
1719     return result;
1720 }
1721 
1722 
1723 /* --------------------------------------------------------------------------------------------- */
1724 /**
1725  * Load new hint and display it.
1726  * IF force is not 0, ignore the timeout.
1727  */
1728 
1729 void
1730 load_hint (gboolean force)
     /* [previous][next][first][last][top][bottom][index][help]  */
1731 {
1732     char *hint;
1733 
1734     if (WIDGET (the_hint)->owner == NULL)
1735         return;
1736 
1737     if (!mc_global.message_visible)
1738     {
1739         label_set_text (the_hint, NULL);
1740         return;
1741     }
1742 
1743     hint = get_random_hint (force);
1744 
1745     if (hint != NULL)
1746     {
1747         if (*hint != '\0')
1748             set_hintbar (hint);
1749         g_free (hint);
1750     }
1751     else
1752     {
1753         char text[BUF_SMALL];
1754 
1755         g_snprintf (text, sizeof (text), _("GNU Midnight Commander %s\n"), mc_global.mc_version);
1756         set_hintbar (text);
1757     }
1758 }
1759 
1760 /* --------------------------------------------------------------------------------------------- */
1761 /**
1762   * Change current panel in the file manager.
1763   *
1764   * @return current_panel
1765   */
1766 
1767 WPanel *
1768 change_panel (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1769 {
1770     input_complete_free (cmdline);
1771     group_select_next_widget (GROUP (filemanager));
1772     return current_panel;
1773 }
1774 
1775 /* --------------------------------------------------------------------------------------------- */
1776 
1777 /** Save current stat of directories to avoid reloading the panels
1778  * when no modifications have taken place
1779  */
1780 void
1781 save_cwds_stat (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1782 {
1783     if (panels_options.fast_reload)
1784     {
1785         mc_stat (current_panel->cwd_vpath, &(current_panel->dir_stat));
1786         if (get_other_type () == view_listing)
1787             mc_stat (other_panel->cwd_vpath, &(other_panel->dir_stat));
1788     }
1789 }
1790 
1791 /* --------------------------------------------------------------------------------------------- */
1792 
1793 gboolean
1794 quiet_quit_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1795 {
1796     print_last_revert = TRUE;
1797     return quit_cmd_internal (1);
1798 }
1799 
1800 /* --------------------------------------------------------------------------------------------- */
1801 
1802 /** Run the main dialog that occupies the whole screen */
1803 gboolean
1804 do_nc (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1805 {
1806     gboolean ret;
1807 
1808 #ifdef USE_INTERNAL_EDIT
1809     edit_stack_init ();
1810 #endif
1811 
1812     filemanager = dlg_create (FALSE, 0, 0, 1, 1, WPOS_FULLSCREEN, FALSE, dialog_colors,
1813                               midnight_callback, NULL, "[main]", NULL);
1814 
1815     /* Check if we were invoked as an editor or file viewer */
1816     if (mc_global.mc_run_mode != MC_RUN_FULL)
1817     {
1818         setup_dummy_mc ();
1819         ret = mc_maybe_editor_or_viewer ();
1820     }
1821     else
1822     {
1823         /* We only need the first idle event to show user menu after start */
1824         widget_idle (WIDGET (filemanager), TRUE);
1825 
1826         setup_mc ();
1827         mc_filehighlight = mc_fhl_new (TRUE);
1828 
1829         create_file_manager ();
1830         (void) dlg_run (filemanager);
1831 
1832         mc_fhl_free (&mc_filehighlight);
1833 
1834         ret = TRUE;
1835 
1836         /* widget_destroy destroys even current_panel->cwd_vpath, so we have to save a copy :) */
1837         if (mc_args__last_wd_file != NULL && vfs_current_is_local ())
1838             last_wd_string = g_strdup (vfs_path_as_str (current_panel->cwd_vpath));
1839 
1840         /* don't handle VFS timestamps for dirs opened in panels */
1841         mc_event_destroy (MCEVENT_GROUP_CORE, "vfs_timestamp");
1842 
1843         dir_list_free_list (&panelized_panel.list);
1844     }
1845 
1846     /* Program end */
1847     mc_global.midnight_shutdown = TRUE;
1848     dialog_switch_shutdown ();
1849     done_mc ();
1850     widget_destroy (WIDGET (filemanager));
1851     current_panel = NULL;
1852 
1853 #ifdef USE_INTERNAL_EDIT
1854     edit_stack_free ();
1855 #endif
1856 
1857     if ((quit & SUBSHELL_EXIT) == 0)
1858         tty_clear_screen ();
1859 
1860     return ret;
1861 }
1862 
1863 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */