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

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