menu.c
来自「一个很有名的浏览器」· C语言 代码 · 共 1,071 行 · 第 1/2 页
C
1,071 行
struct string def; assert(ses && uri); if_assert_failed return; /* FIXME: This ``sanity'' checking is mostly for the download code * using this function. They pass ses->download_uri and we have to make * sure that the connection code can download the URI. The reason we do * it before is that then users won't waste time typing a filename and * then discover that the URI can not be downloaded. However it might * be better to introduce a set_session_download_uri() which will do * the checking? --jonas */ if (uri->protocol == PROTOCOL_UNKNOWN) { print_error_dialog(ses, S_UNKNOWN_PROTOCOL, uri, PRI_CANCEL); return; } if (get_protocol_external_handler(uri->protocol)) { print_error_dialog(ses, S_EXTERNAL_PROTOCOL, uri, PRI_CANCEL); return; } if (!init_string(&def)) return; add_to_string(&def, get_opt_str("document.download.directory")); if (def.length && !dir_sep(def.source[def.length - 1])) add_char_to_string(&def, '/'); add_mime_filename_to_string(&def, uri); /* Remove the %-ugliness for display */ decode_uri_string_for_display(&def); if (interactive) { input_dialog(ses->tab->term, NULL, N_("Download"), N_("Save to file"), data, &file_history, MAX_STR_LEN, def.source, 0, 0, check_nonempty, (void (*)(void *, unsigned char *)) std, (void (*)(void *)) cancel); } else { std(data, def.source); } done_string(&def);}voidfree_history_lists(void){ free_list(file_history.entries);#ifdef CONFIG_SCRIPTING trigger_event_name("free-history");#endif}static voidadd_cmdline_bool_option(struct string *string, unsigned char *name){ if (!get_cmd_opt_bool(name)) return; add_to_string(string, " -"); add_to_string(string, name);}voidopen_uri_in_new_window(struct session *ses, struct uri *uri, enum term_env_type env){ int ring = get_cmd_opt_int("session-ring"); struct string parameters; int id; assert(env && ses); if_assert_failed return; id = add_session_info(ses, uri); if (id < 1) return; if (!init_string(¶meters)) return; add_format_to_string(¶meters, "-base-session %d", id); if (ring) add_format_to_string(¶meters, " -session-ring %d", ring); /* No URI means open new (clean) window possibly without connecting to * the current master so add command line options to properly clone the * current master */ if (!uri) { /* Adding -touch-files will only lead to problems */ add_cmdline_bool_option(¶meters, "localhost"); add_cmdline_bool_option(¶meters, "no-home"); add_cmdline_bool_option(¶meters, "no-connect"); } open_new_window(ses->tab->term, path_to_exe, env, parameters.source); done_string(¶meters);}/* Open a link in a new xterm. */voidsend_open_in_new_window(struct terminal *term, const struct open_in_new *open, struct session *ses){ struct document_view *doc_view; struct link *link; struct uri *uri; assert(term && open && ses); if_assert_failed return; doc_view = current_frame(ses); assert(doc_view && doc_view->vs && doc_view->document); if_assert_failed return; link = get_current_link(doc_view); if (!link) return; uri = get_link_uri(ses, doc_view, link); if (!uri) return; open_uri_in_new_window(ses, uri, open->env); done_uri(uri);}voidsend_open_new_window(struct terminal *term, const struct open_in_new *open, struct session *ses){ open_uri_in_new_window(ses, NULL, open->env);}voidopen_in_new_window(struct terminal *term, void *func_, void *ses_){ menu_func func = func_; struct session *ses = ses_; struct menu_item *mi; int posibilities; assert(term && ses && func); if_assert_failed return; switch (can_open_in_new(term)) { case 0: return; case 1: mi = NULL; break; default: mi = new_menu(FREE_LIST); if (!mi) return; } foreach_open_in_new (posibilities, term->environment) { const struct open_in_new *oi = &open_in_new[posibilities]; if (mi == NULL) { func(term, (void *) oi, ses); return; } add_to_menu(&mi, oi->text, NULL, ACT_MAIN_NONE, func, (void *) oi, 0); } do_menu(term, mi, ses, 1);}voidadd_new_win_to_menu(struct menu_item **mi, unsigned char *text, struct terminal *term){ int c = can_open_in_new(term); if (!c) return; /* The URI is saved as session info in the master and not sent to the * instance in the new window so with -no-connect or -no-home enabled * it is not possible to open links URIs. For -anonymous one window * should be enough. */ if (get_cmd_opt_bool("no-connect") || get_cmd_opt_bool("no-home") || get_cmd_opt_bool("anonymous")) return; add_to_menu(mi, text, NULL, ACT_MAIN_OPEN_LINK_IN_NEW_WINDOW, open_in_new_window, send_open_in_new_window, c - 1 ? SUBMENU : 0);}static voiddo_pass_uri_to_command(struct terminal *term, void *command_, void *xxx){ unsigned char *command = command_; exec_on_terminal(term, command, "", 0); mem_free(command);}/* TODO: * - Support for passing MIME type * - Merge this function with rewrite_uri(), subst_cmd(), subst_file() * and subst_url(). */static unsigned char *format_command(unsigned char *format, struct uri *uri){ struct string string; if (!init_string(&string)) return NULL; while (*format) { int pos = 0; while (format[pos] && format[pos] != '%') pos++; add_bytes_to_string(&string, format, pos); format += pos; if (*format != '%') continue; format++; switch (*format) { case 'c': { unsigned char *str = struri(uri); int length = get_real_uri_length(uri); add_shell_quoted_to_string(&string, str, length); break; } case '%': add_char_to_string(&string, '%'); break; default: add_bytes_to_string(&string, format - 1, 2); break; } if (*format) format++; } return string.source;}enum frame_event_statuspass_uri_to_command(struct session *ses, struct document_view *doc_view, int which_type){ struct list_head *tree = get_opt_tree("document.uri_passing"); enum pass_uri_type type = which_type; struct menu_item *items; struct option *option; struct uri *uri; int commands = 0; switch (type) { case PASS_URI_FRAME: uri = get_uri_reference(doc_view->document->uri); break; case PASS_URI_LINK: { struct link *link = get_current_link(doc_view); if (!link) return FRAME_EVENT_OK; uri = get_link_uri(ses, doc_view, link); if (!uri) return FRAME_EVENT_OK; break; } default: case PASS_URI_TAB: uri = get_uri_reference(ses->doc_view->document->uri); }; items = new_menu(FREE_LIST | FREE_TEXT | FREE_DATA | NO_INTL); if (!items) { done_uri(uri); return FRAME_EVENT_OK; } foreach (option, *tree) { unsigned char *text, *data; if (!strcmp(option->name, "_template_")) continue; text = stracpy(option->name); if (!text) continue; data = format_command(option->value.string, uri); if (!data) { mem_free(text); continue; } add_to_menu(&items, text, NULL, ACT_MAIN_NONE, do_pass_uri_to_command, data, 0); commands++; } done_uri(uri); if (commands > 1) { do_menu(ses->tab->term, items, ses, 1); } else { if (commands == 1) do_pass_uri_to_command(ses->tab->term, items->data, ses); else mem_free(items->data); mem_free(items->text); mem_free(items); } return FRAME_EVENT_OK;}voidadd_uri_command_to_menu(struct menu_item **mi, enum pass_uri_type type){ struct list_head *tree = get_opt_tree("document.uri_passing"); struct option *option; int commands = 0; enum menu_item_flags flags = NO_FLAG; int action; unsigned char *text; switch (type) { case PASS_URI_FRAME: action = ACT_MAIN_FRAME_EXTERNAL_COMMAND; text = N_("~Pass frame URI to external command"); break; case PASS_URI_LINK: action = ACT_MAIN_LINK_EXTERNAL_COMMAND; text = N_("Pass link URI to e~xternal command"); break; default: case PASS_URI_TAB: action = ACT_MAIN_TAB_EXTERNAL_COMMAND; text = N_("Pass tab URI to e~xternal command"); }; foreach (option, *tree) { if (!strcmp(option->name, "_template_")) continue; commands++; if (commands > 1) { flags = SUBMENU; break; } } if (commands == 0) return; add_to_menu(mi, text, NULL, action, NULL, NULL, flags);}/* The file completion menu always has two non selectable menu item at the * start. First is the 'Directory:' or 'Files:' text and then a separator. */#define FILE_COMPLETION_MENU_OFFSET 2static struct menu_item empty_directory_menu[] = { INIT_MENU_ITEM(N_("Empty directory"), NULL, ACT_MAIN_NONE, NULL, NULL, NO_SELECT), NULL_MENU_ITEM};/* Builds the file completion menu. If there is only one item it is selected * else the menu is launched. */static voidcomplete_file_menu(struct terminal *term, int no_elevator, void *data, menu_func file_func, menu_func dir_func, unsigned char *dirname, unsigned char *filename){ struct menu_item *menu = new_menu(FREE_LIST | NO_INTL); struct directory_entry *entries, *entry; int filenamelen = strlen(filename); int direntries = 0, fileentries = 0; if (!menu) return; entries = get_directory_entries(dirname, 1); if (!entries) { mem_free(menu); return; } for (entry = entries; entry->name; entry++) { unsigned char *text; int is_dir = (*entry->attrib == 'd'); int is_file = (*entry->attrib == '-'); mem_free(entry->attrib); if ((!is_dir && !is_file) || !file_can_read(entry->name)) { mem_free(entry->name); continue; } text = get_filename_position(entry->name); if (strncmp(filename, text, filenamelen) || (no_elevator && !strcmp("..", text))) { mem_free(entry->name); continue; } if (is_dir) { if (!direntries) { add_to_menu(&menu, _("Directories:", term), NULL, ACT_MAIN_NONE, NULL, NULL, NO_SELECT); add_menu_separator(&menu); } add_to_menu(&menu, text, NULL, ACT_MAIN_NONE, dir_func, entry->name, FREE_DATA | SUBMENU); direntries++; } else { if (!fileentries) { if (direntries) add_menu_separator(&menu); add_to_menu(&menu, _("Files:", term), NULL, ACT_MAIN_NONE, NULL, NULL, NO_SELECT); add_menu_separator(&menu); } add_to_menu(&menu, text, NULL, ACT_MAIN_NONE, file_func, entry->name, FREE_DATA); fileentries++; } } mem_free(entries); if (direntries == 0 && fileentries == 0) { mem_free(menu); return; } /* Only one entry */ if (direntries + fileentries == 1) { unsigned char *text = menu[FILE_COMPLETION_MENU_OFFSET].data; mem_free(menu); if (fileentries) { /* Complete what is already there */ file_func(term, text, data); return; } /* For single directory entries open the lonely subdir if it is * not the parent elevator. */ if (strcmp(&text[strlen(dirname)], "..")) { dir_func(term, text, data); } else { do_menu(term, empty_directory_menu, NULL, 0); \ } mem_free(text); } else { /* Start with the first directory or file entry selected */ do_menu(term, menu, data, 0); }}/* Prepares the launching of the file completion menu by expanding the @path * and splitting it in directory and file name part. */voidauto_complete_file(struct terminal *term, int no_elevator, unsigned char *path, menu_func file_func, menu_func dir_func, void *data){ struct uri *uri; unsigned char *dirname; unsigned char *filename; assert(term && data && file_func && dir_func && data); if (get_cmd_opt_bool("anonymous")) return; if (!*path) path = "./"; /* Use the URI translation to handle ./ and ../ and ~/ expansion */ uri = get_translated_uri(path, term->cwd); if (!uri) return; if (uri->protocol != PROTOCOL_FILE) { path = NULL; } else { path = get_uri_string(uri, URI_PATH); } done_uri(uri); if (!path) return; filename = get_filename_position(path); if (*filename && file_is_dir(path)) { filename = path + strlen(path); } else if (*filename && file_exists(path)) { /* Complete any tilde expansion */ file_func(term, path, data); return; } /* Split the path into @dirname and @filename */ dirname = path; path = filename; filename = stracpy(path); *path = 0; /* Make sure the dirname has an ending slash */ if (!dir_sep(path[-1])) { unsigned char separator = *dirname; int dirnamelen = path - dirname; insert_in_string(&dirname, dirnamelen, &separator, 1); } complete_file_menu(term, no_elevator, data, file_func, dir_func, dirname, filename); mem_free(dirname); mem_free(filename);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?