/* Sub-loop of the main loop that "asynchronously" queries for the input * performing the following tasks while waiting for input: * - checks for new IPC messages; * - checks whether contents of displayed directories changed; * - redraws UI if requested. * Returns KEY_CODE_YES for functional keys, OK for wide character and ERR * otherwise (e.g. after timeout). */ static int get_char_async_loop(WINDOW *win, wint_t *c, int timeout) { const int IPC_F = (ipc_enabled() && ipc_server()) ? 10 : 1; do { int i; if(should_check_views_for_changes()) { check_view_for_changes(curr_view); check_view_for_changes(other_view); } process_scheduled_updates(); for(i = 0; i < IPC_F; ++i) { int result; ipc_check(); wtimeout(win, MIN(cfg.min_timeout_len, timeout)/IPC_F); result = compat_wget_wch(win, c); if(result != ERR) { return result; } process_scheduled_updates(); } timeout -= cfg.min_timeout_len; } while(timeout > 0); return ERR; }
/* Sub-loop of the main loop that "asynchronously" queries for the input * performing the following tasks while waiting for input: * - checks for new IPC messages; * - checks whether contents of displayed directories changed; * - redraws UI if requested. * Returns KEY_CODE_YES for functional keys (preprocesses *c in this case), OK * for wide character and ERR otherwise (e.g. after timeout). */ static int get_char_async_loop(WINDOW *win, wint_t *c, int timeout) { const int IPC_F = ipc_enabled() ? 10 : 1; do { int i; int delay_slice = DIV_ROUND_UP(MIN(cfg.min_timeout_len, timeout), IPC_F); #ifdef __PDCURSES__ /* pdcurses performs delays in 50 ms intervals (1/20 of a second). */ delay_slice = MAX(50, delay_slice); #endif if(should_check_views_for_changes()) { check_view_for_changes(curr_view); check_view_for_changes(other_view); } process_scheduled_updates(); for(i = 0; i < IPC_F && timeout > 0; ++i) { int result; ipc_check(curr_stats.ipc); wtimeout(win, delay_slice); timeout -= delay_slice; if(suggestions_are_visible) { /* Redraw suggestion box as it might have been hidden due to other * redraws. */ display_suggestion_box(curr_input_buf); } /* Update cursor before waiting for input. Modes set cursor correctly * within corresponding windows, but we need to call refresh on one of * them to make it active. */ update_hardware_cursor(); result = compat_wget_wch(win, c); if(result != ERR) { if(result == KEY_CODE_YES) { *c = K(*c); } else if(*c == L'\0') { *c = WC_C_SPACE; } return result; } process_scheduled_updates(); } } while(timeout > 0); return ERR; }
/* Entry-point. Has same semantics as main(). */ static int vifm_main(int argc, char *argv[]) { /* TODO: refactor vifm_main() function */ static const int quit = 0; char **files = NULL; int nfiles = 0; int lwin_cv, rwin_cv; char dir[PATH_MAX + 1]; if(get_start_cwd(dir, sizeof(dir)) != 0) { return -1; } args_parse(&vifm_args, argc, argv, dir); args_process(&vifm_args, 1); lwin_cv = (strcmp(vifm_args.lwin_path, "-") == 0 && vifm_args.lwin_handle); rwin_cv = (strcmp(vifm_args.rwin_path, "-") == 0 && vifm_args.rwin_handle); if(lwin_cv || rwin_cv) { files = read_stream_lines(stdin, &nfiles, 1, NULL, NULL); if(reopen_term_stdin() != 0) { free_string_array(files, nfiles); return EXIT_FAILURE; } } (void)setlocale(LC_ALL, ""); srand(time(NULL)); cfg_init(); if(vifm_args.logging) { init_logger(1, vifm_args.startup_log_path); } init_filelists(); tabs_init(); regs_init(); cfg_discover_paths(); reinit_logger(cfg.log_file); /* Commands module also initializes bracket notation and variables. */ init_commands(); init_builtin_functions(); update_path_env(1); if(stats_init(&cfg) != 0) { free_string_array(files, nfiles); puts("Error during session status initialization."); return -1; } /* Tell file type module what function to use to check availability of * external programs. */ ft_init(&external_command_exists); /* This should be called before loading any configuration file. */ ft_reset(curr_stats.exec_env_type == EET_EMULATOR_WITH_X); init_option_handlers(); if(!vifm_args.no_configs) { /* vifminfo must be processed this early so that it can restore last visited * directory. */ read_info_file(0); } curr_stats.ipc = ipc_init(vifm_args.server_name, &parse_received_arguments, &eval_received_expression); if(ipc_enabled() && curr_stats.ipc == NULL) { fputs("Failed to initialize IPC unit", stderr); return -1; } /* Export chosen server name to parsing unit. */ { var_t var = var_from_str(ipc_get_name(curr_stats.ipc)); setvar("v:servername", var); var_free(var); } args_process(&vifm_args, 0); bg_init(); fops_init(&enter_prompt_mode, &prompt_msg_custom); set_view_path(&lwin, vifm_args.lwin_path); set_view_path(&rwin, vifm_args.rwin_path); if(need_to_switch_active_pane(vifm_args.lwin_path, vifm_args.rwin_path)) { swap_view_roles(); } load_initial_directory(&lwin, dir); load_initial_directory(&rwin, dir); /* Force split view when two paths are specified on command-line. */ if(vifm_args.lwin_path[0] != '\0' && vifm_args.rwin_path[0] != '\0') { curr_stats.number_of_windows = 2; } /* Prepare terminal for further operations. */ curr_stats.original_stdout = reopen_term_stdout(); if(curr_stats.original_stdout == NULL) { free_string_array(files, nfiles); return -1; } if(!setup_ncurses_interface()) { free_string_array(files, nfiles); return -1; } init_modes(); un_init(&undo_perform_func, NULL, &ui_cancellation_requested, &cfg.undo_levels); load_view_options(curr_view); curr_stats.load_stage = 1; /* Make v:count exist during processing configuration. */ set_count_vars(0); if(!vifm_args.no_configs) { load_scheme(); cfg_load(); } if(lwin_cv || rwin_cv) { flist_custom_set(lwin_cv ? &lwin : &rwin, "-", dir, files, nfiles); } free_string_array(files, nfiles); cs_load_pairs(); cs_write(); setup_signals(); /* Ensure trash directories exist, it might not have been called during * configuration file sourcing if there is no `set trashdir=...` command. */ (void)set_trash_dir(cfg.trash_dir); check_path_for_file(&lwin, vifm_args.lwin_path, vifm_args.lwin_handle); check_path_for_file(&rwin, vifm_args.rwin_path, vifm_args.rwin_handle); curr_stats.load_stage = 2; /* Update histories of the views to ensure that their current directories, * which might have been set using command-line parameters, are stored in the * history. This is not done automatically as history manipulation should be * postponed until views are fully loaded, otherwise there is no correct * information about current file and relative cursor position. */ flist_hist_save(&lwin, NULL, NULL, -1); flist_hist_save(&rwin, NULL, NULL, -1); /* Trigger auto-commands for initial directories. */ if(!lwin_cv) { (void)vifm_chdir(flist_get_dir(&lwin)); vle_aucmd_execute("DirEnter", flist_get_dir(&lwin), &lwin); } if(!rwin_cv) { (void)vifm_chdir(flist_get_dir(&rwin)); vle_aucmd_execute("DirEnter", flist_get_dir(&rwin), &rwin); } update_screen(UT_FULL); modes_update(); /* Run startup commands after loading file lists into views, so that commands * like +1 work. */ exec_startup_commands(&vifm_args); curr_stats.load_stage = 3; event_loop(&quit); return 0; }