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(&parameters)) return;	add_format_to_string(&parameters, "-base-session %d", id);	if (ring) add_format_to_string(&parameters, " -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(&parameters, "localhost");		add_cmdline_bool_option(&parameters, "no-home");		add_cmdline_bool_option(&parameters, "no-connect");	}	open_new_window(ses->tab->term, path_to_exe, env, parameters.source);	done_string(&parameters);}/* 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 + -
显示快捷键?