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

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