Merge branch '2087_standalone_mcedit_crash'
[kaloumi3.git] / src / main.c
blob27e34b7684c9d35dc257d6a5e630fee27f55fc24
1 /* Main program for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
5 Written by: 1994, 1995, 1996, 1997 Miguel de Icaza
6 1994, 1995 Janne Kukonlehto
7 1997 Norbert Warmuth
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 /** \file main.c
24 * \brief Source: this is a main module
27 #include <config.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <locale.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
40 #include <pwd.h> /* for username in xterm title */
42 #include "lib/global.h"
44 #include "lib/tty/tty.h"
45 #include "lib/tty/mouse.h"
46 #include "lib/tty/key.h" /* For init_key() */
47 #include "lib/tty/win.h" /* xterm_flag */
49 #include "lib/skin.h"
51 #include "lib/mcconfig.h"
52 #include "lib/filehighlight.h"
53 #include "lib/fileloc.h" /* MC_USERCONF_DIR */
55 #include "lib/vfs/mc-vfs/vfs.h" /* vfs_translate_url() */
57 #ifdef ENABLE_VFS_SMB
58 #include "lib/vfs/mc-vfs/smbfs.h" /* smbfs_set_debug() */
59 #endif /* ENABLE_VFS_SMB */
61 #ifdef ENABLE_VFS
62 #include "lib/vfs/mc-vfs/gc.h"
63 #endif
65 #include "lib/strutil.h"
67 #include "src/args.h"
69 #include "dir.h"
70 #include "dialog.h"
71 #include "menu.h"
72 #include "panel.h"
73 #include "option.h"
74 #include "tree.h"
75 #include "treestore.h"
76 #include "consaver/cons.saver.h"
77 #include "subshell.h"
78 #include "setup.h" /* save_setup() */
79 #include "boxes.h" /* sort_box() */
80 #include "layout.h"
81 #include "cmd.h" /* Normal commands */
82 #include "hotlist.h"
83 #include "panelize.h"
84 #include "learn.h" /* learn_keys() */
85 #include "listmode.h"
86 #include "execute.h"
87 #include "ext.h" /* For flush_extension_file() */
88 #include "widget.h"
89 #include "command.h"
90 #include "wtools.h"
91 #include "cmddef.h" /* CK_ cmd name const */
92 #include "user.h" /* user_file_menu_cmd() */
95 #include "chmod.h"
96 #include "chown.h"
97 #include "achown.h"
99 #include "main.h"
102 #ifdef USE_INTERNAL_EDIT
103 # include "src/editor/edit.h"
104 #endif
106 #ifdef HAVE_CHARSET
107 #include "charsets.h"
108 #endif /* HAVE_CHARSET */
111 #include "keybind.h" /* type global_keymap_t */
113 /* When the modes are active, left_panel, right_panel and tree_panel */
114 /* Point to a proper data structure. You should check with the functions */
115 /* get_current_type and get_other_type the types of the panels before using */
116 /* This pointer variables */
118 /* The structures for the panels */
119 WPanel *left_panel = NULL;
120 WPanel *right_panel = NULL;
122 mc_fhl_t *mc_filehighlight;
124 /* The pointer to the tree */
125 WTree *the_tree = NULL;
127 /* The Menubar */
128 struct WMenuBar *the_menubar = NULL;
130 /* Pointers to the selected and unselected panel */
131 WPanel *current_panel = NULL;
133 /* Set if the command is being run from the "Right" menu */
134 int is_right = 0;
136 /* Set when main loop should be terminated */
137 volatile int quit = 0;
139 /* Set if you want the possible completions dialog for the first time */
140 int show_all_if_ambiguous = 0;
142 /* Set when cd symlink following is desirable (bash mode) */
143 int cd_symlinks = 1;
145 /* If set then dialogs just clean the screen when refreshing, else */
146 /* they do a complete refresh, refreshing all the parts of the program */
147 int fast_refresh = 0;
149 /* If true, marking a files moves the cursor down */
150 int mark_moves_down = 1;
152 /* If true, at startup the user-menu is invoked */
153 int auto_menu = 0;
155 /* If true, then the +, - and \ keys have their special meaning only if the
156 * command line is emtpy, otherwise they behave like regular letters
158 int only_leading_plus_minus = 1;
160 int pause_after_run = pause_on_dumb_terminals;
162 /* It true saves the setup when quitting */
163 int auto_save_setup = 1;
165 #ifdef HAVE_CHARSET
167 * Don't restrict the output on the screen manager level,
168 * the translation tables take care of it.
170 #define full_eight_bits (1)
171 #define eight_bit_clean (1)
172 #else /* HAVE_CHARSET */
173 /* If true, allow characters in the range 160-255 */
174 int eight_bit_clean = 1;
176 * If true, also allow characters in the range 128-159.
177 * This is reported to break on many terminals (xterm, qansi-m).
179 int full_eight_bits = 0;
180 #endif /* !HAVE_CHARSET */
183 * If utf-8 terminal utf8_display = 1
184 * Display bits set UTF-8
187 int utf8_display = 0;
189 /* If true use the internal viewer */
190 int use_internal_view = 1;
192 /* Have we shown the fast-reload warning in the past? */
193 int fast_reload_w = 0;
195 /* Move page/item? When clicking on the top or bottom of a panel */
196 int mouse_move_pages = 1;
198 /* If true: l&r arrows are used to chdir if the input line is empty */
199 int navigate_with_arrows = 0;
201 /* The prompt */
202 const char *mc_prompt = NULL;
204 /* The widget where we draw the prompt */
205 WLabel *the_prompt;
207 /* The hint bar */
208 WLabel *the_hint;
210 /* The button bar */
211 WButtonBar *the_bar;
213 /* Mouse type: GPM, xterm or none */
214 Mouse_Type use_mouse_p = MOUSE_NONE;
216 /* If on, default for "No" in delete operations */
217 int safe_delete = 0;
219 /* Controls screen clearing before an exec */
220 int clear_before_exec = 1;
222 /* Asks for confirmation before deleting a file */
223 int confirm_delete = 1;
225 /* Asks for confirmation before deleting a hotlist entry */
226 int confirm_directory_hotlist_delete = 1;
228 /* Asks for confirmation before overwriting a file */
229 int confirm_overwrite = 1;
231 /* Asks for confirmation before executing a program by pressing enter */
232 int confirm_execute = 0;
234 /* Asks for confirmation before leaving the program */
235 int confirm_exit = 1;
237 /* Asks for confirmation before clean up of history */
238 int confirm_history_cleanup = 1;
240 /* Asks for confirmation when using F3 to view a directory and there
241 are tagged files */
242 int confirm_view_dir = 0;
244 /* This flag indicates if the pull down menus by default drop down */
245 int drop_menus = 0;
247 /* The dialog handle for the main program */
248 Dlg_head *midnight_dlg = NULL;
250 /* Subshell: if set, then the prompt was not saved on CONSOLE_SAVE */
251 /* We need to paint it after CONSOLE_RESTORE, see: load_prompt */
252 int update_prompt = 0;
254 /* The home directory */
255 const char *home_dir = NULL;
257 /* Tab size */
258 int option_tab_spacing = 8;
260 /* The value of the other directory, only used when loading the setup */
261 char *other_dir = NULL;
263 /* Only used at program boot */
264 int boot_current_is_left = 1;
266 static char *this_dir = NULL;
268 /* If this is true, then when browsing the tree the other window will
269 * automatically reload it's directory with the contents of the currently
270 * selected directory.
272 int xtree_mode = 0;
274 /* If set, then print to the given file the last directory we were at */
275 static char *last_wd_string = NULL;
276 /* Set to 1 to suppress printing the last directory */
277 static int print_last_revert = 0;
279 /* File name to view if argument was supplied */
280 const char *view_one_file = NULL;
282 /* File name to edit if argument was supplied */
283 const char *edit_one_file = NULL;
285 /* Line to start the editor on */
286 static int edit_one_file_start_line = 0;
288 /* Used so that widgets know if they are being destroyed or
289 shut down */
290 int midnight_shutdown = 0;
292 /* The user's shell */
293 char *shell = NULL;
295 /* mc_home: The home of MC - /etc/mc or defined by MC_DATADIR */
296 char *mc_home = NULL;
298 /* mc_home_alt: Alternative home of MC - deprecated /usr/share/mc */
299 char *mc_home_alt = NULL;
301 /* Define this function for glib-style error handling */
302 GQuark
303 mc_main_error_quark (void)
305 return g_quark_from_static_string (PACKAGE);
308 #ifdef USE_INTERNAL_EDIT
309 GArray *editor_keymap = NULL;
310 GArray *editor_x_keymap = NULL;
311 #endif
312 GArray *viewer_keymap = NULL;
313 GArray *viewer_hex_keymap = NULL;
314 GArray *main_keymap = NULL;
315 GArray *main_x_keymap = NULL;
316 GArray *panel_keymap = NULL;
317 GArray *input_keymap = NULL;
318 GArray *tree_keymap = NULL;
319 GArray *help_keymap = NULL;
321 const global_keymap_t *main_map;
322 const global_keymap_t *main_x_map;
324 /* Save current stat of directories to avoid reloading the panels */
325 /* when no modifications have taken place */
326 void
327 save_cwds_stat (void)
329 if (fast_reload) {
330 mc_stat (current_panel->cwd, &(current_panel->dir_stat));
331 if (get_other_type () == view_listing)
332 mc_stat (other_panel->cwd, &(other_panel->dir_stat));
336 #ifdef HAVE_SUBSHELL_SUPPORT
337 void
338 do_update_prompt (void)
340 if (update_prompt) {
341 printf ("\r\n%s", subshell_prompt);
342 fflush (stdout);
343 update_prompt = 0;
346 #endif /* HAVE_SUBSHELL_SUPPORT */
348 void
349 change_panel (void)
351 free_completions (cmdline);
352 dlg_one_down (midnight_dlg);
355 /* Stop MC main dialog and the current dialog if it exists.
356 * Needed to provide fast exit from MC viewer or editor on shell exit */
357 static void
358 stop_dialogs (void)
360 midnight_dlg->running = 0;
361 if (current_dlg) {
362 current_dlg->running = 0;
366 static int
367 quit_cmd_internal (int quiet)
369 int q = quit;
371 if (quiet || !confirm_exit) {
372 q = 1;
373 } else {
374 if (query_dialog
375 (_(" The Midnight Commander "),
376 _(" Do you really want to quit the Midnight Commander? "), D_NORMAL,
377 2, _("&Yes"), _("&No")) == 0)
378 q = 1;
380 if (q) {
381 #ifdef HAVE_SUBSHELL_SUPPORT
382 if (!use_subshell)
383 stop_dialogs ();
384 else if ((q = exit_subshell ()))
385 #endif
386 stop_dialogs ();
388 if (q)
389 quit |= 1;
390 return quit;
393 static void
394 quit_cmd (void)
396 quit_cmd_internal (0);
399 void
400 quiet_quit_cmd (void)
402 print_last_revert = 1;
403 quit_cmd_internal (1);
406 /* Wrapper for do_subshell_chdir, check for availability of subshell */
407 void
408 subshell_chdir (const char *directory)
410 #ifdef HAVE_SUBSHELL_SUPPORT
411 if (use_subshell) {
412 if (vfs_current_is_local ())
413 do_subshell_chdir (directory, 0, 1);
415 #endif /* HAVE_SUBSHELL_SUPPORT */
418 void
419 directory_history_add (struct WPanel *panel, const char *dir)
421 char *tmp;
423 tmp = g_strdup (dir);
424 strip_password (tmp, 1);
426 panel->dir_history = list_append_unique (panel->dir_history, tmp);
430 * If we moved to the parent directory move the selection pointer to
431 * the old directory name; If we leave VFS dir, remove FS specificator.
433 * You do _NOT_ want to add any vfs aware code here. <pavel@ucw.cz>
435 static const char *
436 get_parent_dir_name (const char *cwd, const char *lwd)
438 const char *p;
439 if (strlen (lwd) > strlen (cwd))
440 if ((p = strrchr (lwd, PATH_SEP)) && !strncmp (cwd, lwd, p - lwd) &&
441 ((gsize)strlen (cwd) == (gsize) p - (gsize) lwd || (p == lwd && cwd[0] == PATH_SEP &&
442 cwd[1] == '\0'))) {
443 return (p + 1);
445 return NULL;
449 * Changes the current directory of the panel.
450 * Don't record change in the directory history.
452 static int
453 _do_panel_cd (WPanel *panel, const char *new_dir, enum cd_enum cd_type)
455 const char *directory;
456 char *olddir;
457 char temp[MC_MAXPATHLEN];
458 char *translated_url;
460 if (cd_type == cd_parse_command) {
461 while (*new_dir == ' ')
462 new_dir++;
465 olddir = g_strdup (panel->cwd);
466 new_dir = translated_url = vfs_translate_url (new_dir);
468 /* Convert *new_path to a suitable pathname, handle ~user */
470 if (cd_type == cd_parse_command) {
471 if (!strcmp (new_dir, "-")) {
472 strcpy (temp, panel->lwd);
473 new_dir = temp;
476 directory = *new_dir ? new_dir : home_dir;
478 if (mc_chdir (directory) == -1) {
479 strcpy (panel->cwd, olddir);
480 g_free (olddir);
481 g_free (translated_url);
482 return 0;
484 g_free (translated_url);
486 /* Success: save previous directory, shutdown status of previous dir */
487 strcpy (panel->lwd, olddir);
488 free_completions (cmdline);
490 mc_get_current_wd (panel->cwd, sizeof (panel->cwd) - 2);
492 vfs_release_path (olddir);
494 subshell_chdir (panel->cwd);
496 /* Reload current panel */
497 panel_clean_dir (panel);
498 panel->count =
499 do_load_dir (panel->cwd, &panel->dir, panel->current_sort_field->sort_routine,
500 panel->reverse, panel->case_sensitive,
501 panel->exec_first, panel->filter);
502 try_to_select (panel, get_parent_dir_name (panel->cwd, olddir));
503 load_hint (0);
504 panel->dirty = 1;
505 update_xterm_title_path ();
507 g_free (olddir);
509 return 1;
513 * Changes the current directory of the panel.
514 * Record change in the directory history.
517 do_panel_cd (struct WPanel *panel, const char *new_dir, enum cd_enum cd_type)
519 int r;
521 r = _do_panel_cd (panel, new_dir, cd_type);
522 if (r)
523 directory_history_add (panel, panel->cwd);
524 return r;
528 do_cd (const char *new_dir, enum cd_enum exact)
530 return (do_panel_cd (current_panel, new_dir, exact));
533 void
534 directory_history_next (WPanel *panel)
536 GList *nextdir;
538 nextdir = g_list_next (panel->dir_history);
540 if (!nextdir)
541 return;
543 if (_do_panel_cd (panel, (char *) nextdir->data, cd_exact))
544 panel->dir_history = nextdir;
547 void
548 directory_history_prev (WPanel *panel)
550 GList *prevdir;
552 prevdir = g_list_previous (panel->dir_history);
554 if (!prevdir)
555 return;
557 if (_do_panel_cd (panel, (char *) prevdir->data, cd_exact))
558 panel->dir_history = prevdir;
561 void
562 directory_history_list (WPanel *panel)
564 char *s;
566 s = show_hist (&panel->dir_history, &panel->widget);
568 if (s != NULL) {
569 if (_do_panel_cd (panel, s, cd_exact))
570 directory_history_add (panel, panel->cwd);
571 else
572 message (D_ERROR, MSG_ERROR, _("Cannot change directory"));
573 g_free (s);
577 #ifdef HAVE_SUBSHELL_SUPPORT
579 load_prompt (int fd, void *unused)
581 (void) fd;
582 (void) unused;
584 if (!read_subshell_prompt ())
585 return 0;
587 /* Don't actually change the prompt if it's invisible */
588 if (current_dlg == midnight_dlg && command_prompt) {
589 char *tmp_prompt;
590 int prompt_len;
592 tmp_prompt = strip_ctrl_codes (subshell_prompt);
593 prompt_len = str_term_width1 (tmp_prompt);
595 /* Check for prompts too big */
596 if (COLS > 8 && prompt_len > COLS - 8) {
597 tmp_prompt[COLS - 8] = '\0';
598 prompt_len = COLS - 8;
600 mc_prompt = tmp_prompt;
601 label_set_text (the_prompt, mc_prompt);
602 winput_set_origin ((WInput *) cmdline, prompt_len,
603 COLS - prompt_len);
605 /* since the prompt has changed, and we are called from one of the
606 * tty_get_event channels, the prompt updating does not take place
607 * automatically: force a cursor update and a screen refresh
609 update_cursor (midnight_dlg);
610 mc_refresh ();
612 update_prompt = 1;
613 return 0;
615 #endif /* HAVE_SUBSHELL_SUPPORT */
617 void
618 sort_cmd (void)
620 WPanel *p;
621 const panel_field_t *sort_order;
623 if (!SELECTED_IS_PANEL)
624 return;
626 p = MENU_PANEL;
627 sort_order = sort_box (p->current_sort_field, &p->reverse,
628 &p->case_sensitive,
629 &p->exec_first);
631 panel_set_sort_order (p, sort_order);
635 static void
636 treebox_cmd (void)
638 char *sel_dir;
640 sel_dir = tree_box (selection (current_panel)->fname);
641 if (sel_dir) {
642 do_cd (sel_dir, cd_exact);
643 g_free (sel_dir);
647 #ifdef LISTMODE_EDITOR
648 static void
649 listmode_cmd (void)
651 char *newmode;
653 if (get_current_type () != view_listing)
654 return;
656 newmode = listmode_edit (current_panel->user_format);
657 if (!newmode)
658 return;
660 g_free (current_panel->user_format);
661 current_panel->list_type = list_user;
662 current_panel->user_format = newmode;
663 set_panel_formats (current_panel);
665 do_refresh ();
667 #endif /* LISTMODE_EDITOR */
669 /* NOTICE: hotkeys specified here are overriden in menubar_paint_idx (alex) */
670 static GList *
671 create_panel_menu (void)
673 GList *entries = NULL;
675 entries = g_list_append (entries, menu_entry_create (_("&Listing mode..."), CK_ListingCmd));
676 entries = g_list_append (entries, menu_entry_create (_("&Quick view"), CK_QuickViewCmd));
677 entries = g_list_append (entries, menu_entry_create (_("&Info" ), CK_InfoCmd));
678 entries = g_list_append (entries, menu_entry_create (_("&Tree"), CK_TreeCmd));
679 entries = g_list_append (entries, menu_separator_create ());
680 entries = g_list_append (entries, menu_entry_create (_("&Sort order..."), CK_Sort));
681 entries = g_list_append (entries, menu_separator_create ());
682 entries = g_list_append (entries, menu_entry_create (_("&Filter..."), CK_FilterCmd));
683 #ifdef HAVE_CHARSET
684 entries = g_list_append (entries, menu_separator_create ());
685 entries = g_list_append (entries, menu_entry_create (_("&Encoding..."), CK_PanelSetPanelEncoding));
686 #endif
687 #ifdef USE_NETCODE
688 entries = g_list_append (entries, menu_separator_create ());
689 #ifdef ENABLE_VFS_MCFS
690 entries = g_list_append (entries, menu_entry_create (_("&Network link..."), CK_NetlinkCmd));
691 #endif
692 entries = g_list_append (entries, menu_entry_create (_("FT&P link..."), CK_FtplinkCmd));
693 entries = g_list_append (entries, menu_entry_create (_("S&hell link..."), CK_FishlinkCmd));
694 #ifdef ENABLE_VFS_SMB
695 entries = g_list_append (entries, menu_entry_create (_("SM&B link..."), CK_SmblinkCmd));
696 #endif /* ENABLE_VFS_SMB */
697 #endif
698 entries = g_list_append (entries, menu_separator_create ());
699 entries = g_list_append (entries, menu_entry_create (_("&Rescan"), CK_RereadCmd));
701 return entries;
704 static GList *
705 create_file_menu (void)
707 GList *entries = NULL;
709 entries = g_list_append (entries, menu_entry_create (_("&View"), CK_ViewCmd));
710 entries = g_list_append (entries, menu_entry_create (_("Vie&w file..."), CK_ViewFileCmd));
711 entries = g_list_append (entries, menu_entry_create (_("&Filtered view"), CK_FilteredViewCmd));
712 entries = g_list_append (entries, menu_entry_create (_("&Edit"), CK_EditCmd));
713 entries = g_list_append (entries, menu_entry_create (_("&Copy"), CK_CopyCmd));
714 entries = g_list_append (entries, menu_entry_create (_("C&hmod"), CK_ChmodCmd));
715 entries = g_list_append (entries, menu_entry_create (_("&Link"), CK_LinkCmd));
716 entries = g_list_append (entries, menu_entry_create (_("&SymLink"), CK_SymlinkCmd));
717 entries = g_list_append (entries, menu_entry_create (_("Edit s&ymlink"), CK_EditSymlinkCmd));
718 entries = g_list_append (entries, menu_entry_create (_("Ch&own"), CK_ChownCmd));
719 entries = g_list_append (entries, menu_entry_create (_("&Advanced chown"), CK_ChownAdvancedCmd));
720 entries = g_list_append (entries, menu_entry_create (_("&Rename/Move"), CK_RenameCmd));
721 entries = g_list_append (entries, menu_entry_create (_("&Mkdir"), CK_MkdirCmd));
722 entries = g_list_append (entries, menu_entry_create (_("&Delete"), CK_DeleteCmd));
723 entries = g_list_append (entries, menu_entry_create (_("&Quick cd"), CK_QuickCdCmd));
724 entries = g_list_append (entries, menu_separator_create ());
725 entries = g_list_append (entries, menu_entry_create (_("Select &group"), CK_SelectCmd));
726 entries = g_list_append (entries, menu_entry_create (_("U&nselect group"), CK_UnselectCmd));
727 entries = g_list_append (entries, menu_entry_create (_("Reverse selec&tion"), CK_ReverseSelectionCmd));
728 entries = g_list_append (entries, menu_separator_create ());
729 entries = g_list_append (entries, menu_entry_create (_("E&xit"), CK_QuitCmd));
731 return entries;
734 static GList *
735 create_command_menu (void)
737 /* I know, I'm lazy, but the tree widget when it's not running
738 * as a panel still has some problems, I have not yet finished
739 * the WTree widget port, sorry.
741 GList *entries = NULL;
743 entries = g_list_append (entries, menu_entry_create (_("&User menu"), CK_UserMenuCmd));
744 entries = g_list_append (entries, menu_entry_create (_("&Directory tree"), CK_TreeBoxCmd));
745 entries = g_list_append (entries, menu_entry_create (_("&Find file"), CK_FindCmd));
746 entries = g_list_append (entries, menu_entry_create (_("S&wap panels"), CK_SwapCmd));
747 entries = g_list_append (entries, menu_entry_create (_("Switch &panels on/off"), CK_ShowCommandLine));
748 entries = g_list_append (entries, menu_entry_create (_("&Compare directories"), CK_CompareDirsCmd));
749 entries = g_list_append (entries, menu_entry_create (_("E&xternal panelize"), CK_ExternalPanelize));
750 entries = g_list_append (entries, menu_entry_create (_("Show directory s&izes"), CK_SingleDirsizeCmd));
751 entries = g_list_append (entries, menu_separator_create ());
752 entries = g_list_append (entries, menu_entry_create (_("Command &history"), CK_HistoryCmd));
753 entries = g_list_append (entries, menu_entry_create (_("Di&rectory hotlist"), CK_QuickChdirCmd));
754 #ifdef ENABLE_VFS
755 entries = g_list_append (entries, menu_entry_create (_("&Active VFS list"), CK_ReselectVfs));
756 #endif
757 #ifdef WITH_BACKGROUND
758 entries = g_list_append (entries, menu_entry_create (_("&Background jobs"), CK_JobsCmd));
759 #endif
760 entries = g_list_append (entries, menu_separator_create ());
761 #ifdef USE_EXT2FSLIB
762 entries = g_list_append (entries, menu_entry_create (_("&Undelete files (ext2fs only)"), CK_UndeleteCmd));
763 #endif
764 #ifdef LISTMODE_EDITOR
765 entries = g_list_append (entries, menu_entry_create (_("&Listing format edit"), CK_ListmodeCmd));
766 #endif
767 #if defined (USE_EXT2FSLIB) || defined (LISTMODE_EDITOR)
768 entries = g_list_append (entries, menu_separator_create ());
769 #endif
770 entries = g_list_append (entries, menu_entry_create (_("Edit &extension file"), CK_EditExtFileCmd));
771 entries = g_list_append (entries, menu_entry_create (_("Edit &menu file"), CK_EditMcMenuCmd));
772 entries = g_list_append (entries, menu_entry_create (_("Edit hi&ghlighting group file"), CK_EditFhlFileCmd));
774 return entries;
777 static GList *
778 create_options_menu (void)
780 GList *entries = NULL;
782 entries = g_list_append (entries, menu_entry_create (_("&Configuration..."), CK_ConfigureBox));
783 entries = g_list_append (entries, menu_entry_create (_("&Layout..."), CK_LayoutCmd));
784 entries = g_list_append (entries, menu_entry_create (_("C&onfirmation..."), CK_ConfirmBox));
785 entries = g_list_append (entries, menu_entry_create (_("&Display bits..."), CK_DisplayBitsBox));
786 entries = g_list_append (entries, menu_entry_create (_("Learn &keys..."), CK_LearnKeys));
787 #ifdef ENABLE_VFS
788 entries = g_list_append (entries, menu_entry_create (_("&Virtual FS..."), CK_ConfigureVfs));
789 #endif
790 entries = g_list_append (entries, menu_separator_create ());
791 entries = g_list_append (entries, menu_entry_create (_("&Save setup"), CK_SaveSetupCmd));
793 return entries;
796 void
797 init_menu (void)
799 menubar_add_menu (the_menubar,
800 create_menu (horizontal_split ? _("&Above") : _("&Left"),
801 create_panel_menu (), "[Left and Right Menus]"));
802 menubar_add_menu (the_menubar,
803 create_menu (_("&File"), create_file_menu (), "[File Menu]"));
804 menubar_add_menu (the_menubar,
805 create_menu (_("&Command"), create_command_menu (), "[Command Menu]"));
806 menubar_add_menu (the_menubar,
807 create_menu (_("&Options"), create_options_menu (), "[Options Menu]"));
808 menubar_add_menu (the_menubar,
809 create_menu (horizontal_split ? _("&Below") : _("&Right"),
810 create_panel_menu (), "[Left and Right Menus]"));
813 void
814 done_menu (void)
816 menubar_set_menu (the_menubar, NULL);
819 static void
820 menu_last_selected_cmd (void)
822 the_menubar->is_active = TRUE;
823 the_menubar->is_dropped = (drop_menus != 0);
824 the_menubar->previous_widget = midnight_dlg->current->dlg_id;
825 dlg_select_widget (the_menubar);
828 static void
829 menu_cmd (void)
831 if (the_menubar->is_active)
832 return;
834 if ((get_current_index () == 0) == (current_panel->active != 0))
835 the_menubar->selected = 0;
836 else
837 the_menubar->selected = g_list_length (the_menubar->menu) - 1;
838 menu_last_selected_cmd ();
841 static char *
842 midnight_get_shortcut (unsigned long command)
844 const char *ext_map;
845 const char *shortcut = NULL;
847 shortcut = lookup_keymap_shortcut (main_map, command);
848 if (shortcut != NULL)
849 return g_strdup (shortcut);
851 shortcut = lookup_keymap_shortcut (panel_map, command);
852 if (shortcut != NULL)
853 return g_strdup (shortcut);
855 ext_map = lookup_keymap_shortcut (main_map, CK_StartExtMap1);
856 if (ext_map != NULL)
857 shortcut = lookup_keymap_shortcut (main_x_map, command);
858 if (shortcut != NULL)
859 return g_strdup_printf ("%s %s", ext_map, shortcut);
861 return NULL;
864 /* Flag toggling functions */
865 void
866 toggle_fast_reload (void)
868 fast_reload = !fast_reload;
869 if (fast_reload_w == 0 && fast_reload) {
870 message (D_NORMAL, _(" Information "),
872 (" Using the fast reload option may not reflect the exact \n"
873 " directory contents. In this case you'll need to do a \n"
874 " manual reload of the directory. See the man page for \n"
875 " the details. "));
876 fast_reload_w = 1;
880 void
881 toggle_mix_all_files (void)
883 mix_all_files = !mix_all_files;
884 update_panels (UP_RELOAD, UP_KEEPSEL);
887 void
888 toggle_show_backup (void)
890 show_backups = !show_backups;
891 update_panels (UP_RELOAD, UP_KEEPSEL);
894 void
895 toggle_show_hidden (void)
897 show_dot_files = !show_dot_files;
898 update_panels (UP_RELOAD, UP_KEEPSEL);
901 static void
902 toggle_panels_split (void)
904 horizontal_split = !horizontal_split;
905 layout_change ();
906 do_refresh();
909 void
910 toggle_kilobyte_si (void)
912 kilobyte_si = !kilobyte_si;
913 update_panels (UP_RELOAD, UP_KEEPSEL);
917 * Just a hack for allowing url-like pathnames to be accepted from the
918 * command line.
920 static void
921 translated_mc_chdir (char *dir)
923 char *newdir;
925 newdir = vfs_translate_url (dir);
926 mc_chdir (newdir);
927 g_free (newdir);
930 static void
931 create_panels (void)
933 int current_index;
934 int other_index;
935 panel_view_mode_t current_mode, other_mode;
936 char original_dir[BUF_1K] = "\0";
938 if (boot_current_is_left) {
939 current_index = 0;
940 other_index = 1;
941 current_mode = startup_left_mode;
942 other_mode = startup_right_mode;
943 } else {
944 current_index = 1;
945 other_index = 0;
946 current_mode = startup_right_mode;
947 other_mode = startup_left_mode;
949 /* Creates the left panel */
950 if (this_dir) {
951 if (other_dir) {
952 /* Ok, user has specified two dirs, save the original one,
953 * since we may not be able to chdir to the proper
954 * second directory later
956 mc_get_current_wd (original_dir, sizeof (original_dir) - 2);
958 translated_mc_chdir (this_dir);
960 set_display_type (current_index, current_mode);
962 /* The other panel */
963 if (other_dir) {
964 if (original_dir[0] != '\0')
965 translated_mc_chdir (original_dir);
966 translated_mc_chdir (other_dir);
968 set_display_type (other_index, other_mode);
970 if (startup_left_mode == view_listing) {
971 current_panel = left_panel;
972 } else {
973 if (right_panel)
974 current_panel = right_panel;
975 else
976 current_panel = left_panel;
979 /* Create the nice widgets */
980 cmdline = command_new (0, 0, 0);
981 the_prompt = label_new (0, 0, mc_prompt);
982 the_prompt->transparent = 1;
983 the_bar = buttonbar_new (keybar_visible);
985 the_hint = label_new (0, 0, 0);
986 the_hint->transparent = 1;
987 the_hint->auto_adjust_cols = 0;
988 the_hint->widget.cols = COLS;
990 the_menubar = menubar_new (0, 0, COLS, NULL);
993 static void
994 copy_current_pathname (void)
996 char *cwd_path;
997 if (!command_prompt)
998 return;
1000 cwd_path = remove_encoding_from_path (current_panel->cwd);
1001 command_insert (cmdline, cwd_path, 0);
1003 if (cwd_path [strlen (cwd_path ) - 1] != PATH_SEP)
1004 command_insert (cmdline, PATH_SEP_STR, 0);
1005 g_free (cwd_path);
1008 static void
1009 copy_other_pathname (void)
1011 char *cwd_path;
1013 if (get_other_type () != view_listing)
1014 return;
1016 if (!command_prompt)
1017 return;
1019 cwd_path = remove_encoding_from_path (other_panel->cwd);
1020 command_insert (cmdline, cwd_path, 0);
1022 if (cwd_path [strlen (cwd_path ) - 1] != PATH_SEP)
1023 command_insert (cmdline, PATH_SEP_STR, 0);
1024 g_free (cwd_path);
1027 static void
1028 copy_readlink (WPanel *panel)
1030 if (!command_prompt)
1031 return;
1032 if (S_ISLNK (selection (panel)->st.st_mode)) {
1033 char buffer[MC_MAXPATHLEN];
1034 char *p =
1035 concat_dir_and_file (panel->cwd, selection (panel)->fname);
1036 int i;
1038 i = mc_readlink (p, buffer, MC_MAXPATHLEN - 1);
1039 g_free (p);
1040 if (i > 0) {
1041 buffer[i] = 0;
1042 command_insert (cmdline, buffer, 1);
1047 static void
1048 copy_current_readlink (void)
1050 copy_readlink (current_panel);
1053 static void
1054 copy_other_readlink (void)
1056 if (get_other_type () == view_listing)
1057 copy_readlink (other_panel);
1060 /* Insert the selected file name into the input line */
1061 static void
1062 copy_prog_name (void)
1064 char *tmp;
1065 if (!command_prompt)
1066 return;
1068 if (get_current_type () == view_tree) {
1069 WTree *tree = (WTree *) get_panel_widget (get_current_index ());
1070 tmp = tree_selected_name (tree);
1071 } else
1072 tmp = selection (current_panel)->fname;
1074 command_insert (cmdline, tmp, 1);
1077 static void
1078 copy_tagged (WPanel *panel)
1080 int i;
1082 if (!command_prompt)
1083 return;
1084 input_disable_update (cmdline);
1085 if (panel->marked) {
1086 for (i = 0; i < panel->count; i++) {
1087 if (panel->dir.list[i].f.marked)
1088 command_insert (cmdline, panel->dir.list[i].fname, 1);
1090 } else {
1091 command_insert (cmdline, panel->dir.list[panel->selected].fname,
1094 input_enable_update (cmdline);
1097 static void
1098 copy_current_tagged (void)
1100 copy_tagged (current_panel);
1103 static void
1104 copy_other_tagged (void)
1106 if (get_other_type () == view_listing)
1107 copy_tagged (other_panel);
1110 void
1111 midnight_set_buttonbar (WButtonBar *b)
1113 buttonbar_set_label (b, 1, Q_("ButtonBar|Help"), main_map, NULL);
1114 buttonbar_set_label (b, 2, Q_("ButtonBar|Menu"), main_map, NULL);
1115 buttonbar_set_label (b, 3, Q_("ButtonBar|View"), main_map, NULL);
1116 buttonbar_set_label (b, 4, Q_("ButtonBar|Edit"), main_map, NULL);
1117 buttonbar_set_label (b, 5, Q_("ButtonBar|Copy"), main_map, NULL);
1118 buttonbar_set_label (b, 6, Q_("ButtonBar|RenMov"), main_map, NULL);
1119 buttonbar_set_label (b, 7, Q_("ButtonBar|Mkdir"), main_map, NULL);
1120 buttonbar_set_label (b, 8, Q_("ButtonBar|Delete"), main_map, NULL);
1121 buttonbar_set_label (b, 9, Q_("ButtonBar|PullDn"), main_map, NULL);
1122 buttonbar_set_label (b, 10, Q_("ButtonBar|Quit"), main_map, NULL);
1125 static gboolean ctl_x_map_enabled = FALSE;
1127 static void
1128 ctl_x_cmd (void)
1130 ctl_x_map_enabled = TRUE;
1133 static cb_ret_t
1134 midnight_execute_cmd (Widget *sender, unsigned long command)
1136 cb_ret_t res = MSG_HANDLED;
1138 (void) sender;
1140 switch (command) {
1141 case CK_AddHotlist:
1142 add2hotlist_cmd ();
1143 break;
1144 case CK_ChmodCmd:
1145 chmod_cmd ();
1146 break;
1147 case CK_ChownCmd:
1148 chown_cmd ();
1149 break;
1150 case CK_ChownAdvancedCmd:
1151 chown_advanced_cmd ();
1152 break;
1153 case CK_CompareDirsCmd:
1154 compare_dirs_cmd ();
1155 break;
1156 case CK_ConfigureBox:
1157 configure_box ();
1158 break;
1159 #ifdef ENABLE_VFS
1160 case CK_ConfigureVfs:
1161 configure_vfs ();
1162 break;
1163 #endif
1164 case CK_ConfirmBox:
1165 confirm_box ();
1166 break;
1167 case CK_CopyCmd:
1168 copy_cmd ();
1169 break;
1170 case CK_CopyCurrentPathname:
1171 copy_current_pathname ();
1172 break;
1173 case CK_CopyCurrentReadlink:
1174 copy_current_readlink ();
1175 break;
1176 case CK_CopyCurrentTagged:
1177 copy_current_tagged ();
1178 break;
1179 case CK_CopyOtherPathname:
1180 copy_other_pathname ();
1181 break;
1182 case CK_CopyOtherReadlink:
1183 copy_other_readlink ();
1184 break;
1185 case CK_CopyOtherTagged:
1186 copy_other_tagged ();
1187 break;
1188 case CK_DeleteCmd:
1189 delete_cmd ();
1190 break;
1191 case CK_DisplayBitsBox:
1192 display_bits_box ();
1193 break;
1194 case CK_EditCmd:
1195 edit_cmd ();
1196 break;
1197 case CK_EditExtFileCmd:
1198 ext_cmd ();
1199 break;
1200 case CK_EditFhlFileCmd:
1201 edit_fhl_cmd ();
1202 break;
1203 case CK_EditMcMenuCmd:
1204 edit_mc_menu_cmd ();
1205 break;
1206 case CK_EditSymlinkCmd:
1207 edit_symlink_cmd ();
1208 break;
1209 case CK_ExternalPanelize:
1210 external_panelize ();
1211 break;
1212 case CK_FilterCmd:
1213 filter_cmd ();
1214 break;
1215 case CK_FilteredViewCmd:
1216 filtered_view_cmd ();
1217 break;
1218 case CK_FindCmd:
1219 find_cmd ();
1220 break;
1221 #if defined (USE_NETCODE)
1222 case CK_FishlinkCmd:
1223 fishlink_cmd ();
1224 break;
1225 case CK_FtplinkCmd:
1226 ftplink_cmd ();
1227 break;
1228 #endif
1229 case CK_HelpCmd:
1230 help_cmd ();
1231 break;
1232 case CK_HistoryCmd:
1233 history_cmd ();
1234 break;
1235 case CK_InfoCmd:
1236 if (sender == (Widget *) the_menubar)
1237 info_cmd (); /* mwnu */
1238 else
1239 info_cmd_no_menu (); /* shortcut or buttonbar */
1240 break;
1241 #ifdef WITH_BACKGROUND
1242 case CK_JobsCmd:
1243 jobs_cmd ();
1244 break;
1245 #endif
1246 case CK_LayoutCmd:
1247 layout_cmd ();
1248 break;
1249 case CK_LearnKeys:
1250 learn_keys ();
1251 break;
1252 case CK_LinkCmd:
1253 link_cmd ();
1254 break;
1255 case CK_ListingCmd:
1256 listing_cmd ();
1257 break;
1258 #ifdef LISTMODE_EDITOR
1259 case CK_ListmodeCmd:
1260 listmode_cmd ();
1261 break;
1262 #endif
1263 case CK_MenuCmd:
1264 menu_cmd ();
1265 break;
1266 case CK_MenuLastSelectedCmd:
1267 menu_last_selected_cmd ();
1268 break;
1269 case CK_MkdirCmd:
1270 mkdir_cmd ();
1271 break;
1272 #if defined (USE_NETCODE) && defined (ENABLE_VFS_MCFS)
1273 case CK_NetlinkCmd:
1274 netlink_cmd ();
1275 break;
1276 #endif
1277 #ifdef HAVE_CHARSET
1278 case CK_PanelSetPanelEncoding:
1279 encoding_cmd ();
1280 break;
1281 #endif
1282 case CK_QuickCdCmd:
1283 quick_cd_cmd ();
1284 break;
1285 case CK_QuickChdirCmd:
1286 quick_chdir_cmd ();
1287 break;
1288 case CK_QuickViewCmd:
1289 if (sender == (Widget *) the_menubar)
1290 quick_view_cmd (); /* menu */
1291 else
1292 quick_cmd_no_menu (); /* shortcut or buttonabr */
1293 break;
1294 case CK_QuietQuitCmd:
1295 quiet_quit_cmd ();
1296 break;
1297 case CK_QuitCmd:
1298 quit_cmd ();
1299 break;
1300 case CK_RenameCmd:
1301 rename_cmd ();
1302 break;
1303 case CK_RereadCmd:
1304 reread_cmd ();
1305 break;
1306 #ifdef ENABLE_VFS
1307 case CK_ReselectVfs:
1308 reselect_vfs ();
1309 break;
1310 #endif
1311 case CK_ReverseSelectionCmd:
1312 reverse_selection_cmd ();
1313 break;
1314 case CK_SaveSetupCmd:
1315 save_setup_cmd ();
1316 break;
1317 case CK_SelectCmd:
1318 select_cmd ();
1319 break;
1320 case CK_ShowCommandLine:
1321 view_other_cmd ();
1322 break;
1323 case CK_SingleDirsizeCmd:
1324 smart_dirsize_cmd ();
1325 break;
1326 #if defined (USE_NETCODE) && defined (ENABLE_VFS_SMB)
1327 case CK_SmblinkCmd:
1328 smblink_cmd ();
1329 break;
1330 #endif /* USE_NETCODE && ENABLE_VFS_SMB */
1331 case CK_Sort:
1332 sort_cmd ();
1333 break;
1334 case CK_StartExtMap1:
1335 ctl_x_cmd ();
1336 break;
1337 case CK_SuspendCmd:
1338 suspend_cmd ();
1339 break;
1340 case CK_SwapCmd:
1341 swap_cmd ();
1342 break;
1343 case CK_SymlinkCmd:
1344 symlink_cmd ();
1345 break;
1346 case CK_ToggleListingCmd:
1347 toggle_listing_cmd ();
1348 break;
1349 case CK_ToggleShowHidden:
1350 toggle_show_hidden ();
1351 break;
1352 case CK_TogglePanelsSplit:
1353 toggle_panels_split ();
1354 break;
1355 case CK_TreeCmd:
1356 tree_cmd ();
1357 break;
1358 case CK_TreeBoxCmd:
1359 treebox_cmd ();
1360 break;
1361 #ifdef USE_EXT2FSLIB
1362 case CK_UndeleteCmd:
1363 undelete_cmd ();
1364 break;
1365 #endif
1366 case CK_UnselectCmd:
1367 unselect_cmd ();
1368 break;
1369 case CK_UserMenuCmd:
1370 user_file_menu_cmd ();
1371 break;
1372 case CK_ViewCmd:
1373 view_cmd ();
1374 break;
1375 case CK_ViewFileCmd:
1376 view_file_cmd ();
1377 break;
1378 default:
1379 res = MSG_NOT_HANDLED;
1382 return res;
1385 static void
1386 init_xterm_support (void)
1388 const char *termvalue;
1390 termvalue = getenv ("TERM");
1391 if (!termvalue || !(*termvalue)) {
1392 fputs (_("The TERM environment variable is unset!\n"), stderr);
1393 exit (1);
1396 /* Check mouse capabilities */
1397 xmouse_seq = tty_tgetstr ("Km");
1399 if (strcmp (termvalue, "cygwin") == 0) {
1400 mc_args__force_xterm = 1;
1401 use_mouse_p = MOUSE_DISABLED;
1404 if (mc_args__force_xterm || strncmp (termvalue, "xterm", 5) == 0
1405 || strncmp (termvalue, "konsole", 7) == 0
1406 || strncmp (termvalue, "rxvt", 4) == 0
1407 || strcmp (termvalue, "Eterm") == 0
1408 || strcmp (termvalue, "dtterm") == 0) {
1409 xterm_flag = 1;
1411 /* Default to the standard xterm sequence */
1412 if (!xmouse_seq) {
1413 xmouse_seq = ESC_STR "[M";
1416 /* Enable mouse unless explicitly disabled by --nomouse */
1417 if (use_mouse_p != MOUSE_DISABLED) {
1418 const char *color_term = getenv ("COLORTERM");
1419 if (strncmp (termvalue, "rxvt", 4) == 0 ||
1420 (color_term != NULL && strncmp (color_term, "rxvt", 4) == 0) ||
1421 strcmp (termvalue, "Eterm") == 0) {
1422 use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
1423 } else {
1424 use_mouse_p = MOUSE_XTERM_BUTTON_EVENT_TRACKING;
1430 static void
1431 setup_mc (void)
1433 #ifdef HAVE_SLANG
1434 tty_display_8bit (full_eight_bits != 0);
1435 #else
1436 tty_display_8bit (eight_bit_clean != 0);
1437 #endif
1439 #ifdef HAVE_SUBSHELL_SUPPORT
1440 if (use_subshell)
1441 add_select_channel (subshell_pty, load_prompt, 0);
1442 #endif /* !HAVE_SUBSHELL_SUPPORT */
1444 tty_setup_sigwinch (sigwinch_handler);
1446 if ((tty_baudrate () < 9600) || tty_is_slow ())
1447 verbose = 0;
1449 init_xterm_support ();
1450 init_mouse ();
1453 static void
1454 setup_dummy_mc (void)
1456 char d[MC_MAXPATHLEN];
1458 mc_get_current_wd (d, MC_MAXPATHLEN);
1459 setup_mc ();
1460 mc_chdir (d);
1463 static void check_codeset()
1465 const char *current_system_codepage = NULL;
1467 current_system_codepage = str_detect_termencoding();
1469 #ifdef HAVE_CHARSET
1471 const char *_display_codepage;
1473 _display_codepage = get_codepage_id (display_codepage);
1475 if (! strcmp(_display_codepage, current_system_codepage)) {
1476 utf8_display = str_isutf8 (current_system_codepage);
1477 return;
1480 display_codepage = get_codepage_index (current_system_codepage);
1481 if (display_codepage == -1) {
1482 display_codepage = 0;
1485 mc_config_set_string(mc_main_config, "Misc", "display_codepage", cp_display);
1487 #endif
1488 utf8_display = str_isutf8 (current_system_codepage);
1491 static void
1492 done_screen (void)
1494 if (!(quit & SUBSHELL_EXIT))
1495 clr_scr ();
1496 tty_reset_shell_mode ();
1497 tty_noraw_mode ();
1498 tty_keypad (FALSE);
1499 tty_colors_done ();
1502 static void
1503 done_mc (void)
1505 disable_mouse ();
1507 /* Setup shutdown
1509 * We sync the profiles since the hotlist may have changed, while
1510 * we only change the setup data if we have the auto save feature set
1513 if (auto_save_setup)
1514 save_setup (); /* does also call save_hotlist */
1515 else {
1516 save_hotlist ();
1517 save_panel_types ();
1519 done_screen ();
1520 vfs_add_current_stamps ();
1523 /* This should be called after destroy_dlg since panel widgets
1524 * save their state on the profiles
1526 static void
1527 done_mc_profile (void)
1529 done_setup ();
1532 static cb_ret_t
1533 midnight_callback (Dlg_head *h, Widget *sender,
1534 dlg_msg_t msg, int parm, void *data)
1536 unsigned long command;
1538 switch (msg) {
1539 case DLG_INIT:
1540 setup_panels ();
1541 return MSG_HANDLED;
1543 case DLG_DRAW:
1544 load_hint (1);
1545 /* We handle the special case of the output lines */
1546 if (console_flag && output_lines)
1547 show_console_contents (output_start_y,
1548 LINES - output_lines - keybar_visible -
1549 1, LINES - keybar_visible - 1);
1550 return MSG_HANDLED;
1552 case DLG_RESIZE:
1553 setup_panels ();
1554 menubar_arrange (the_menubar);
1555 return MSG_HANDLED;
1557 case DLG_IDLE:
1558 /* We only need the first idle event to show user menu after start */
1559 set_idle_proc (h, 0);
1561 if (boot_current_is_left)
1562 dlg_select_widget (get_panel_widget (0));
1563 else
1564 dlg_select_widget (get_panel_widget (1));
1566 if (auto_menu)
1567 midnight_execute_cmd (NULL, CK_UserMenuCmd);
1568 return MSG_HANDLED;
1570 case DLG_KEY:
1571 if (ctl_x_map_enabled) {
1572 ctl_x_map_enabled = FALSE;
1573 command = lookup_keymap_command (main_x_map, parm);
1574 if (command != CK_Ignore_Key)
1575 return midnight_execute_cmd (NULL, command);
1578 /* FIXME: should handle all menu shortcuts before this point */
1579 if (the_menubar->is_active)
1580 return MSG_NOT_HANDLED;
1582 if (parm == '\t')
1583 free_completions (cmdline);
1585 if (parm == '\n') {
1586 size_t i;
1588 for (i = 0; cmdline->buffer[i] && (cmdline->buffer[i] == ' ' ||
1589 cmdline->buffer[i] == '\t'); i++)
1591 if (cmdline->buffer[i]) {
1592 send_message ((Widget *) cmdline, WIDGET_KEY, parm);
1593 return MSG_HANDLED;
1595 stuff (cmdline, "", 0);
1596 cmdline->point = 0;
1599 /* Ctrl-Enter and Alt-Enter */
1600 if (((parm & ~(KEY_M_CTRL | KEY_M_ALT)) == '\n')
1601 && (parm & (KEY_M_CTRL | KEY_M_ALT))) {
1602 copy_prog_name ();
1603 return MSG_HANDLED;
1606 /* Ctrl-Shift-Enter */
1607 if (parm == (KEY_M_CTRL | KEY_M_SHIFT | '\n')) {
1608 copy_current_pathname ();
1609 copy_prog_name ();
1610 return MSG_HANDLED;
1613 if ((!alternate_plus_minus || !(console_flag || xterm_flag))
1614 && !quote && !current_panel->searching) {
1615 if (!only_leading_plus_minus) {
1616 /* Special treatement, since the input line will eat them */
1617 if (parm == '+') {
1618 select_cmd ();
1619 return MSG_HANDLED;
1622 if (parm == '\\' || parm == '-') {
1623 unselect_cmd ();
1624 return MSG_HANDLED;
1627 if (parm == '*') {
1628 reverse_selection_cmd ();
1629 return MSG_HANDLED;
1631 } else if (!command_prompt || !cmdline->buffer[0]) {
1632 /* Special treatement '+', '-', '\', '*' only when this is
1633 * first char on input line
1636 if (parm == '+') {
1637 select_cmd ();
1638 return MSG_HANDLED;
1641 if (parm == '\\' || parm == '-') {
1642 unselect_cmd ();
1643 return MSG_HANDLED;
1646 if (parm == '*') {
1647 reverse_selection_cmd ();
1648 return MSG_HANDLED;
1652 return MSG_NOT_HANDLED;
1654 case DLG_HOTKEY_HANDLED:
1655 if ((get_current_type () == view_listing) && current_panel->searching) {
1656 current_panel->searching = 0;
1657 current_panel->dirty = 1;
1659 return MSG_HANDLED;
1661 case DLG_UNHANDLED_KEY:
1662 if (command_prompt) {
1663 cb_ret_t v;
1665 v = send_message ((Widget *) cmdline, WIDGET_KEY, parm);
1666 if (v == MSG_HANDLED)
1667 return MSG_HANDLED;
1670 if (ctl_x_map_enabled) {
1671 ctl_x_map_enabled = FALSE;
1672 command = lookup_keymap_command (main_x_map, parm);
1673 } else
1674 command = lookup_keymap_command (main_map, parm);
1676 return (command == CK_Ignore_Key)
1677 ? MSG_NOT_HANDLED
1678 : midnight_execute_cmd (NULL, command);
1680 case DLG_POST_KEY:
1681 if (!the_menubar->is_active)
1682 update_dirty_panels ();
1683 return MSG_HANDLED;
1685 case DLG_ACTION:
1686 /* shortcut */
1687 if (sender == NULL)
1688 midnight_execute_cmd (NULL, parm);
1689 /* message from menu */
1690 else if (sender == (Widget *) the_menubar)
1691 midnight_execute_cmd (sender, parm);
1692 /* message from buttonbar */
1693 else if (sender == (Widget *) the_bar) {
1694 if (data == NULL)
1695 midnight_execute_cmd (sender, parm);
1696 else
1697 send_message ((Widget *) data, WIDGET_COMMAND, parm);
1699 return MSG_HANDLED;
1701 default:
1702 return default_dlg_callback (h, sender, msg, parm, data);
1706 /* Show current directory in the xterm title */
1707 void
1708 update_xterm_title_path (void)
1710 const char *path;
1711 char host[BUF_TINY];
1712 char *p;
1713 struct passwd *pw = NULL;
1714 char *login = NULL;
1715 int res = 0;
1716 if (xterm_flag && xterm_title) {
1717 path = strip_home_and_password (current_panel->cwd);
1718 res = gethostname(host, sizeof (host));
1719 if ( res ) { /* On success, res = 0 */
1720 host[0] = '\0';
1721 } else {
1722 host[sizeof (host) - 1] = '\0';
1724 pw = getpwuid(getuid());
1725 if ( pw ) {
1726 login = g_strdup_printf ("%s@%s", pw->pw_name, host);
1727 } else {
1728 login = g_strdup (host);
1730 p = g_strdup_printf ("mc [%s]:%s", login, path);
1731 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
1732 g_free (login);
1733 g_free (p);
1734 if (!alternate_plus_minus)
1735 numeric_keypad_mode ();
1736 fflush (stdout);
1741 * Load new hint and display it.
1742 * IF force is not 0, ignore the timeout.
1744 void
1745 load_hint (int force)
1747 char *hint;
1749 if (!the_hint->widget.parent)
1750 return;
1752 if (!message_visible) {
1753 label_set_text (the_hint, NULL);
1754 return;
1757 hint = get_random_hint (force);
1759 if (hint != NULL) {
1760 if (*hint)
1761 set_hintbar (hint);
1762 g_free (hint);
1763 } else {
1764 char text[BUF_SMALL];
1766 g_snprintf (text, sizeof (text), _("GNU Midnight Commander %s\n"),
1767 VERSION);
1768 set_hintbar (text);
1772 static void
1773 create_panels_and_run_mc (void)
1775 midnight_dlg->get_shortcut = midnight_get_shortcut;
1777 create_panels ();
1779 add_widget (midnight_dlg, the_menubar);
1780 init_menu ();
1782 add_widget (midnight_dlg, get_panel_widget (0));
1783 add_widget (midnight_dlg, get_panel_widget (1));
1785 add_widget (midnight_dlg, the_hint);
1786 add_widget (midnight_dlg, cmdline);
1787 add_widget (midnight_dlg, the_prompt);
1789 add_widget (midnight_dlg, the_bar);
1790 midnight_set_buttonbar (the_bar);
1792 /* Run the Midnight Commander if no file was specified in the command line */
1793 run_dlg (midnight_dlg);
1796 /* result must be free'd (I think this should go in util.c) */
1797 static char *
1798 prepend_cwd_on_local (const char *filename)
1800 char *d;
1801 size_t l;
1803 if (!vfs_file_is_local (filename)
1804 || g_path_is_absolute (filename))
1805 return g_strdup (filename);
1807 d = g_malloc (MC_MAXPATHLEN + strlen (filename) + 2);
1808 mc_get_current_wd (d, MC_MAXPATHLEN);
1809 l = strlen (d);
1810 d[l++] = PATH_SEP;
1811 strcpy (d + l, filename);
1812 canonicalize_pathname (d);
1813 return d;
1816 /* Invoke the internal view/edit routine with:
1817 * the default processing and forcing the internal viewer/editor
1819 static void
1820 mc_maybe_editor_or_viewer (void)
1822 if (view_one_file != NULL) {
1823 char *path;
1824 path = prepend_cwd_on_local (view_one_file);
1825 view_file (path, 0, 1);
1826 g_free (path);
1828 #ifdef USE_INTERNAL_EDIT
1829 else
1830 edit_file (edit_one_file, edit_one_file_start_line);
1831 #endif /* USE_INTERNAL_EDIT */
1832 midnight_shutdown = 1;
1833 done_mc ();
1836 /* Run the main dialog that occupies the whole screen */
1837 static void
1838 do_nc (void)
1840 int midnight_colors[DLG_COLOR_NUM];
1841 midnight_colors[0] = mc_skin_color_get("dialog", "_default_");
1842 midnight_colors[1] = mc_skin_color_get("dialog", "focus");
1843 midnight_colors[2] = mc_skin_color_get("dialog", "hotnormal");
1844 midnight_colors[3] = mc_skin_color_get("dialog", "hotfocus");
1846 panel_init ();
1848 midnight_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors, midnight_callback,
1849 "[main]", NULL, DLG_WANT_IDLE);
1851 if ((view_one_file != NULL) || (edit_one_file != NULL))
1852 setup_dummy_mc ();
1853 else
1854 setup_mc ();
1856 /* start check display_codepage and source_codepage */
1857 check_codeset ();
1859 main_map = default_main_map;
1860 if (main_keymap && main_keymap->len > 0)
1861 main_map = (global_keymap_t *) main_keymap->data;
1863 main_x_map = default_main_x_map;
1864 if (main_x_keymap && main_x_keymap->len > 0)
1865 main_x_map = (global_keymap_t *) main_x_keymap->data;
1867 panel_map = default_panel_keymap;
1868 if (panel_keymap && panel_keymap->len > 0)
1869 panel_map = (global_keymap_t *) panel_keymap->data;
1871 input_map = default_input_keymap;
1872 if (input_keymap && input_keymap->len > 0)
1873 input_map = (global_keymap_t *) input_keymap->data;
1875 tree_map = default_tree_keymap;
1876 if (tree_keymap && tree_keymap->len > 0)
1877 tree_map = (global_keymap_t *) tree_keymap->data;
1879 help_map = default_help_keymap;
1880 if (help_keymap && help_keymap->len > 0)
1881 help_map = (global_keymap_t *) help_keymap->data;
1883 /* Check if we were invoked as an editor or file viewer */
1884 if ((view_one_file != NULL) || (edit_one_file != NULL))
1885 mc_maybe_editor_or_viewer ();
1886 else {
1887 create_panels_and_run_mc ();
1889 /* Program end */
1890 midnight_shutdown = 1;
1892 /* destroy_dlg destroys even current_panel->cwd, so we have to save a copy :) */
1893 if (mc_args__last_wd_file && vfs_current_is_local ())
1894 last_wd_string = g_strdup (current_panel->cwd);
1896 done_mc ();
1899 destroy_dlg (midnight_dlg);
1900 panel_deinit ();
1901 current_panel = 0;
1902 done_mc_profile ();
1905 /* POSIX version. The only version we support. */
1906 static void
1907 OS_Setup (void)
1909 const char *shell_env = getenv ("SHELL");
1910 const char *mc_libdir;
1912 if ((shell_env == NULL) || (shell_env[0] == '\0')) {
1913 struct passwd *pwd;
1914 pwd = getpwuid (geteuid ());
1915 if (pwd != NULL)
1916 shell = g_strdup (pwd->pw_shell);
1917 } else
1918 shell = g_strdup (shell_env);
1920 if ((shell == NULL) || (shell[0] == '\0')) {
1921 g_free (shell);
1922 shell = g_strdup ("/bin/sh");
1925 /* This is the directory, where MC was installed, on Unix this is DATADIR */
1926 /* and can be overriden by the MC_DATADIR environment variable */
1927 mc_libdir = getenv ("MC_DATADIR");
1928 if (mc_libdir != NULL) {
1929 mc_home = g_strdup (mc_libdir);
1930 mc_home_alt = g_strdup (SYSCONFDIR);
1931 } else {
1932 mc_home = g_strdup (SYSCONFDIR);
1933 mc_home_alt = g_strdup (DATADIR);
1936 /* This variable is used by the subshell */
1937 home_dir = getenv ("HOME");
1939 if (!home_dir)
1940 home_dir = mc_home;
1943 static void
1944 sigchld_handler_no_subshell (int sig)
1946 #ifdef __linux__
1947 int pid, status;
1949 if (!console_flag)
1950 return;
1952 /* COMMENT: if it were true that after the call to handle_console(..INIT)
1953 the value of console_flag never changed, we could simply not install
1954 this handler at all if (!console_flag && !use_subshell). */
1956 /* That comment is no longer true. We need to wait() on a sigchld
1957 handler (that's at least what the tarfs code expects currently). */
1959 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
1961 if (pid == cons_saver_pid) {
1963 if (WIFSTOPPED (status)) {
1964 /* Someone has stopped cons.saver - restart it */
1965 kill (pid, SIGCONT);
1966 } else {
1967 /* cons.saver has died - disable console saving */
1968 handle_console (CONSOLE_DONE);
1969 console_flag = 0;
1972 /* If we got here, some other child exited; ignore it */
1973 #endif /* __linux__ */
1975 (void) sig;
1978 static void
1979 init_sigchld (void)
1981 struct sigaction sigchld_action;
1983 sigchld_action.sa_handler =
1984 #ifdef HAVE_SUBSHELL_SUPPORT
1985 use_subshell ? sigchld_handler :
1986 #endif /* HAVE_SUBSHELL_SUPPORT */
1987 sigchld_handler_no_subshell;
1989 sigemptyset (&sigchld_action.sa_mask);
1991 #ifdef SA_RESTART
1992 sigchld_action.sa_flags = SA_RESTART;
1993 #else
1994 sigchld_action.sa_flags = 0;
1995 #endif /* !SA_RESTART */
1997 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1) {
1998 #ifdef HAVE_SUBSHELL_SUPPORT
2000 * This may happen on QNX Neutrino 6, where SA_RESTART
2001 * is defined but not implemented. Fallback to no subshell.
2003 use_subshell = 0;
2004 #endif /* HAVE_SUBSHELL_SUPPORT */
2008 static void
2009 mc_main__setup_by_args (int argc, char *argv[])
2011 const char *base;
2012 char *tmp;
2014 if (mc_args__nomouse)
2015 use_mouse_p = MOUSE_DISABLED;
2017 #ifdef USE_NETCODE
2018 if (mc_args__netfs_logfile != NULL) {
2019 mc_setctl ("/#ftp:", VFS_SETCTL_LOGFILE, (void *) mc_args__netfs_logfile);
2020 #ifdef ENABLE_VFS_SMB
2021 smbfs_set_debugf (mc_args__netfs_logfile);
2022 #endif /* ENABLE_VFS_SMB */
2025 #ifdef ENABLE_VFS_SMB
2026 if (mc_args__debug_level != 0)
2027 smbfs_set_debug (mc_args__debug_level);
2028 #endif /* ENABLE_VFS_SMB */
2029 #endif /* USE_NETCODE */
2031 base = x_basename (argv[0]);
2032 tmp = (argc > 0) ? argv[1] : NULL;
2034 if (!STRNCOMP (base, "mce", 3) || !STRCOMP (base, "vi")) {
2035 edit_one_file = "";
2036 if (tmp) {
2038 * Check for filename:lineno, followed by an optional colon.
2039 * This format is used by many programs (especially compilers)
2040 * in error messages and warnings. It is supported so that
2041 * users can quickly copy and paste file locations.
2043 char *end = tmp + strlen (tmp), *p = end;
2044 if (p > tmp && p[-1] == ':')
2045 p--;
2046 while (p > tmp && g_ascii_isdigit ((gchar) p[-1]))
2047 p--;
2048 if (tmp < p && p < end && p[-1] == ':') {
2049 struct stat st;
2050 gchar *fname = g_strndup (tmp, p - 1 - tmp);
2052 * Check that the file before the colon actually exists.
2053 * If it doesn't exist, revert to the old behavior.
2055 if (mc_stat (tmp, &st) == -1 && mc_stat (fname, &st) != -1) {
2056 edit_one_file = fname;
2057 edit_one_file_start_line = atoi (p);
2058 } else {
2059 g_free (fname);
2060 goto try_plus_filename;
2062 } else {
2063 try_plus_filename:
2064 if (*tmp == '+' && g_ascii_isdigit ((gchar) tmp[1])) {
2065 int start_line = atoi (tmp);
2066 if (start_line > 0) {
2067 char *file = (argc > 1) ? argv[2] : NULL;
2068 if (file) {
2069 tmp = file;
2070 edit_one_file_start_line = start_line;
2074 edit_one_file = g_strdup (tmp);
2077 } else if (!STRNCOMP (base, "mcv", 3) || !STRCOMP (base, "view")) {
2078 if (tmp)
2079 view_one_file = g_strdup (tmp);
2080 else {
2081 fputs ("No arguments given to the viewer\n", stderr);
2082 exit (1);
2084 } else {
2085 /* sets the current dir and the other dir */
2086 if (tmp) {
2087 this_dir = g_strdup (tmp);
2088 tmp = (argc > 1) ? argv[2] : NULL;
2089 if (tmp)
2090 other_dir = g_strdup (tmp);
2096 main (int argc, char *argv[])
2098 struct stat s;
2099 char *mc_dir;
2100 GError *error = NULL;
2101 gboolean isInitialized;
2103 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
2104 setlocale (LC_ALL, "");
2105 bindtextdomain ("mc", LOCALEDIR);
2106 textdomain ("mc");
2108 /* Set up temporary directory */
2109 mc_tmpdir ();
2111 OS_Setup ();
2113 str_init_strings (NULL);
2115 vfs_init ();
2117 #ifdef USE_INTERNAL_EDIT
2118 edit_stack_init ();
2119 #endif
2121 #ifdef HAVE_SLANG
2122 SLtt_Ignore_Beep = 1;
2123 #endif
2125 if ( !mc_args_handle (&argc, &argv, "mc"))
2126 return 1;
2128 mc_main__setup_by_args (argc,argv);
2130 /* NOTE: This has to be called before tty_init or whatever routine
2131 calls any define_sequence */
2132 init_key ();
2134 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
2135 handle_console (CONSOLE_INIT);
2137 #ifdef HAVE_SUBSHELL_SUPPORT
2138 /* Don't use subshell when invoked as viewer or editor */
2139 if ((view_one_file != NULL) || (edit_one_file != NULL))
2140 use_subshell = 0;
2142 if (use_subshell)
2143 subshell_get_console_attributes ();
2144 #endif /* HAVE_SUBSHELL_SUPPORT */
2146 /* Install the SIGCHLD handler; must be done before init_subshell() */
2147 init_sigchld ();
2149 /* We need this, since ncurses endwin () doesn't restore the signals */
2150 save_stop_handler ();
2152 /* Must be done before init_subshell, to set up the terminal size: */
2153 /* FIXME: Should be removed and LINES and COLS computed on subshell */
2154 tty_init ((gboolean) mc_args__slow_terminal, (gboolean) mc_args__ugly_line_drawing);
2156 load_setup ();
2158 tty_init_colors (mc_args__disable_colors, mc_args__force_colors);
2160 isInitialized = mc_skin_init(&error);
2162 mc_filehighlight = mc_fhl_new (TRUE);
2164 dlg_set_default_colors ();
2166 if ( ! isInitialized ) {
2167 message (D_ERROR, _("Warning"), "%s", error->message);
2168 g_error_free(error);
2169 error = NULL;
2172 /* create home directory */
2173 /* do it after the screen library initialization to show the error message */
2174 mc_dir = concat_dir_and_file (home_dir, MC_USERCONF_DIR);
2175 canonicalize_pathname (mc_dir);
2176 if ((stat (mc_dir, &s) != 0) && (errno == ENOENT)
2177 && mkdir (mc_dir, 0700) != 0)
2178 message (D_ERROR, _("Warning"),
2179 _("Cannot create %s directory"), mc_dir);
2180 g_free (mc_dir);
2182 #ifdef HAVE_SUBSHELL_SUPPORT
2183 /* Done here to ensure that the subshell doesn't */
2184 /* inherit the file descriptors opened below, etc */
2185 if (use_subshell)
2186 init_subshell ();
2188 #endif /* HAVE_SUBSHELL_SUPPORT */
2190 /* Removing this from the X code let's us type C-c */
2191 load_key_defs ();
2193 load_keymap_defs ();
2195 /* Also done after init_subshell, to save any shell init file messages */
2196 if (console_flag)
2197 handle_console (CONSOLE_SAVE);
2199 if (alternate_plus_minus)
2200 application_keypad_mode ();
2202 #ifdef HAVE_SUBSHELL_SUPPORT
2203 if (use_subshell) {
2204 mc_prompt = strip_ctrl_codes (subshell_prompt);
2205 if (mc_prompt == NULL)
2206 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
2207 } else
2208 #endif /* HAVE_SUBSHELL_SUPPORT */
2209 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
2211 /* Program main loop */
2212 if (!midnight_shutdown)
2213 do_nc ();
2215 /* Save the tree store */
2216 tree_store_save ();
2218 free_keymap_defs ();
2220 /* Virtual File System shutdown */
2221 vfs_shut ();
2223 flush_extension_file (); /* does only free memory */
2225 mc_fhl_free (&mc_filehighlight);
2226 mc_skin_deinit ();
2228 tty_shutdown ();
2230 if (console_flag && !(quit & SUBSHELL_EXIT))
2231 handle_console (CONSOLE_RESTORE);
2232 if (alternate_plus_minus)
2233 numeric_keypad_mode ();
2235 signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
2237 if (console_flag)
2238 handle_console (CONSOLE_DONE);
2239 putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
2241 if (mc_args__last_wd_file && last_wd_string && !print_last_revert
2242 && !edit_one_file && !view_one_file) {
2243 int last_wd_fd =
2244 open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
2245 S_IRUSR | S_IWUSR);
2247 if (last_wd_fd != -1) {
2248 write (last_wd_fd, last_wd_string, strlen (last_wd_string));
2249 close (last_wd_fd);
2252 g_free (last_wd_string);
2254 g_free (mc_home_alt);
2255 g_free (mc_home);
2256 g_free (shell);
2258 done_key ();
2259 #ifdef HAVE_CHARSET
2260 free_codepages_list ();
2261 g_free (autodetect_codeset);
2262 #endif
2263 str_uninit_strings ();
2265 g_free (this_dir);
2266 g_free (other_dir);
2268 #ifdef USE_INTERNAL_EDIT
2269 edit_stack_free ();
2270 #endif
2272 return 0;