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

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