⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gui.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved		by Bram Moolenaar
 *				GUI/Motif support by Robert Webb
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

#include "vim.h"

/* Structure containing all the GUI information */
Gui gui;

/* Set to TRUE after adding/removing menus to ensure they are updated */
int force_menu_update = FALSE;

static void gui_check_screen __ARGS((void));
static void gui_position_components __ARGS((int, int));
static void gui_outstr __ARGS((char_u *, int));
static void gui_delete_lines __ARGS((int row, int count));
static void gui_insert_lines __ARGS((int row, int count));
static int gui_get_menu_cmd_modes __ARGS((char_u *, int, int *, int *));
static char_u *popup_mode_name __ARGS((char_u *name, int idx));
static void  gui_update_menus_recurse __ARGS((GuiMenu *, int));
#ifdef USE_GUI_WIN32
static int gui_add_menu_path __ARGS((char_u *, int, int *, void (*)(), char_u *, int, int));
#else
static int gui_add_menu_path __ARGS((char_u *, int, int *, void (*)(), char_u *, int));
#endif
static int gui_remove_menu __ARGS((GuiMenu **, char_u *, int, int silent));
static void gui_free_menu __ARGS((GuiMenu *));
static void gui_free_menu_string __ARGS((GuiMenu *, int));
static int gui_show_menus __ARGS((char_u *, int));
static void gui_show_menus_recursive __ARGS((GuiMenu *, int, int));
static int menu_name_equal __ARGS((char_u *name, GuiMenu *menu));
static int menu_namecmp __ARGS((char_u *name, char_u *mname));
static void gui_create_initial_menus __ARGS((GuiMenu *, GuiMenu *));
static void gui_update_scrollbars __ARGS((int));
static void gui_update_horiz_scrollbar __ARGS((int));
static WIN *y2win __ARGS((int y));
static int get_menu_mode __ARGS((void));
#ifdef USE_GUI_WIN32
static void gui_create_tearoffs_recurse __ARGS((GuiMenu *menu, const char_u *pname, int *pri_tab, int pri_idx));
static void gui_add_tearoff __ARGS((char_u *tearpath, int *pri_tab, int pri_idx));
static void gui_destroy_tearoffs_recurse __ARGS((GuiMenu *menu));
static int s_tearoffs = FALSE;
#endif

/*
 * The Athena scrollbars can move the thumb to after the end of the scrollbar,
 * this makes the thumb indicate the part of the text that is shown.  Motif
 * can't do this.
 */
#if defined(USE_GUI_ATHENA) || defined(macintosh)
# define SCROLL_PAST_END
#endif

/*
 * While defining the system menu, gui_sys_menu is TRUE.  This avoids
 * overruling of menus that the user already defined.
 */
static int	gui_sys_menu = FALSE;

/*
 * gui_start -- Called when user wants to start the GUI.
 */
    void
gui_start()
{
    char_u  *old_term;
#if defined(UNIX) && !defined(__BEOS__)
    pid_t   pid;
#endif

    old_term = vim_strsave(T_NAME);
    mch_setmouse(FALSE);		/* first switch mouse off */

    /*
     * Set_termname() will call gui_init() to start the GUI.
     * Set the "starting" flag, to indicate that the GUI will start.
     *
     * We don't want to open the GUI window until after we've read .gvimrc,
     * otherwise we don't know what font we will use, and hence we don't know
     * what size the window should be.	So if there are errors in the .gvimrc
     * file, they will have to go to the terminal: Set full_screen to FALSE.
     * full_screen will be set to TRUE again by a successful termcapinit().
     */
    settmode(TMODE_COOK);		/* stop RAW mode */
    if (full_screen)
	cursor_on();			/* needed for ":gui" in .vimrc */
    gui.starting = TRUE;
    full_screen = FALSE;
    termcapinit((char_u *)"builtin_gui");
    gui.starting = FALSE;

    if (!gui.in_use)			/* failed to start GUI */
    {
	termcapinit(old_term);		/* back to old term settings */
	settmode(TMODE_RAW);		/* restart RAW mode */
	set_title_defaults();		/* set 'title' and 'icon' again */
    }

    vim_free(old_term);

#if defined(UNIX) && !defined(__BEOS__)
    /*
     * Quit the current process and continue in the child.
     * Makes "gvim file" disconnect from the shell it was started in.
     * Don't do this when Vim was started with "-f" or the 'f' flag is present
     * in 'guioptions'.
     */
    if (gui.in_use && gui.dofork && vim_strchr(p_guioptions, GO_FORG) == NULL)
    {
	pid = fork();
	if (pid > 0)	    /* Parent */
	    exit(0);
#if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
	/*
	 * Change our process group.  On some systems/shells a CTRL-C in the
	 * shell where Vim was started would otherwise kill gvim!
	 */
	if (pid == 0)	    /* child */
# if defined(HAVE_SETSID)
	    (void)setsid();
# else
	    (void)setpgid(0, 0);
# endif
#endif
    }
#endif
}

/*
 * Call this when vim starts up, whether or not the GUI is started
 */
    void
gui_prepare(argc, argv)
    int	    *argc;
    char    **argv;
{
    /* Menu items may be added before the GUI is started, so set this now */
    gui.root_menu = NULL;
    gui.in_use = FALSE;		    /* No GUI yet (maybe later) */
    gui.starting = FALSE;	    /* No GUI yet (maybe later) */
    gui.dofork = TRUE;		    /* default is to use fork() */
    gui_mch_prepare(argc, argv);
}

/*
 * This is the call which starts the GUI.
 */
    void
gui_init()
{
    WIN		*wp;
    static int	recursive = 0;

    /*
     * It's possible to use ":gui" in a .gvimrc file.  The first halve of this
     * function will then be executed at the first call, the rest by the
     * recursive call.  This allow the window to be opened halfway reading a
     * gvimrc file.
     */
    if (!recursive)
    {
	++recursive;

	gui.window_created = FALSE;
	gui.dying = FALSE;
	gui.in_focus = TRUE;		/* so the guicursor setting works */
	gui.dragged_sb = SBAR_NONE;
	gui.dragged_wp = NULL;
	gui.pointer_hidden = FALSE;
	gui.col = gui.num_cols = 0;
	gui.row = gui.num_rows = 0;

	gui.cursor_is_valid = FALSE;
	gui.scroll_region_top = 0;
	gui.scroll_region_bot = Rows - 1;
	gui.highlight_mask = HL_NORMAL;
	gui.char_width = 1;
	gui.char_height = 1;
	gui.char_ascent = 0;
	gui.border_width = 0;

	gui.norm_font = (GuiFont)NULL;
	gui.bold_font = (GuiFont)NULL;
	gui.ital_font = (GuiFont)NULL;
	gui.boldital_font = (GuiFont)NULL;

	clip_init(TRUE);

	gui.menu_is_active = TRUE;	    /* default: include menu */

	gui.scrollbar_width = gui.scrollbar_height = SB_DEFAULT_WIDTH;
	gui.menu_height = MENU_DEFAULT_HEIGHT;
	gui.menu_width = 0;

	gui.prev_wrap = -1;

	/*
	 * Set up system-wide default menus.
	 */
#ifdef SYS_MENU_FILE
	gui_sys_menu = TRUE;
	do_source((char_u *)SYS_MENU_FILE, FALSE, FALSE);
	gui_sys_menu = FALSE;
#endif

	/*
	 * Switch on the mouse by default, unless the user changed it already.
	 * This can then be changed in the .gvimrc.
	 */
	if (!option_was_set((char_u *)"mouse"))
	    set_string_option_direct((char_u *)"mouse", -1,
							 (char_u *)"a", TRUE);

	/*
	 * If -U option given, use only the initializations from that file and
	 * nothing else.  Skip all initializations for "-U NONE".
	 */
	if (use_gvimrc != NULL)
	{
	    if (STRCMP(use_gvimrc, "NONE") != 0
		    && do_source(use_gvimrc, FALSE, FALSE) != OK)
		EMSG2("Cannot read from \"%s\"", use_gvimrc);
	}
	else
	{
	    /*
	     * Get system wide defaults for gvim, only when file name defined.
	     */
#ifdef SYS_GVIMRC_FILE
	    do_source((char_u *)SYS_GVIMRC_FILE, FALSE, FALSE);
#endif

	    /*
	     * Try to read GUI initialization commands from the following
	     * places:
	     * - environment variable GVIMINIT
	     * - the user gvimrc file (~/.gvimrc)
	     * - the second user gvimrc file ($VIM/.gvimrc for Dos)
	     * The first that exists is used, the rest is ignored.
	     */
	    if (process_env((char_u *)"GVIMINIT") == FAIL
		 && do_source((char_u *)USR_GVIMRC_FILE, TRUE, FALSE) == FAIL)
		{
#ifdef USR_GVIMRC_FILE2
		    (void)do_source((char_u *)USR_GVIMRC_FILE2, TRUE, FALSE);
#endif
		}

	    /*
	     * Read initialization commands from ".gvimrc" in current
	     * directory.  This is only done if the 'exrc' option is set.
	     * Because of security reasons we disallow shell and write
	     * commands now, except for unix if the file is owned by the user
	     * or 'secure' option has been reset in environment of global
	     * ".gvimrc".
	     * Only do this if GVIMRC_FILE is not the same as USR_GVIMRC_FILE,
	     * USR_GVIMRC_FILE2 or SYS_GVIMRC_FILE.
	     */
	    if (p_exrc)
	    {
#ifdef UNIX
		{
		    struct stat s;

		    /* if ".gvimrc" file is not owned by user, set 'secure'
		     * mode */
		    if (stat(GVIMRC_FILE, &s) || s.st_uid != getuid())
			secure = p_secure;
		}
#else
		secure = p_secure;
#endif

		if (       fullpathcmp((char_u *)USR_GVIMRC_FILE,
				     (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
#ifdef SYS_GVIMRC_FILE
			&& fullpathcmp((char_u *)SYS_GVIMRC_FILE,
				     (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
#endif
#ifdef USR_GVIMRC_FILE2
			&& fullpathcmp((char_u *)USR_GVIMRC_FILE2,
				     (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
#endif
			)
		    do_source((char_u *)GVIMRC_FILE, FALSE, FALSE);

		if (secure == 2)
		    need_wait_return = TRUE;
		secure = 0;
	    }
	}

	if (need_wait_return || msg_didany)
	    wait_return(TRUE);

	--recursive;
    }

    /* If recursive call opened the window, return here from the first call */
    if (gui.in_use)
	return;

    /*
     * Create the GUI windows ready for opening.
     */
    gui.in_use = TRUE;		/* Must be set after menus have been set up */
    if (gui_mch_init() == FAIL)
	goto error;

    /*
     * Check validity of any generic resources that may have been loaded.
     */
    if (gui.border_width < 0)
	gui.border_width = 0;

    /*
     * Set up the fonts.
     */
    if (font_opt)
	set_option_value((char_u *)"gfn", 0L, (char_u *)font_opt);
    if (gui_init_font(p_guifont) == FAIL)
	goto error;

    gui.num_cols = Columns;
    gui.num_rows = Rows;
    gui_reset_scroll_region();

    /* Create initial scrollbars */
    for (wp = firstwin; wp; wp = wp->w_next)
    {
	gui_create_scrollbar(&wp->w_scrollbars[SBAR_LEFT], wp);
	gui_create_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], wp);
    }
    gui_create_scrollbar(&gui.bottom_sbar, NULL);

    gui_create_initial_menus(gui.root_menu, NULL);

    /* Configure the desired menu and scrollbars */
    gui_init_which_components(NULL);

    /* All components of the window have been created now */
    gui.window_created = TRUE;

    gui_set_winsize(TRUE);

    /*
     * Actually open the GUI window.
     */
    if (gui_mch_open() != FAIL)
    {
	maketitle();
	init_gui_options();
	return;
    }

error:
    gui.in_use = FALSE;
    clip_init(FALSE);
}

    void
gui_exit(rc)
    int		rc;
{
    free_highlight_fonts();
    gui.in_use = FALSE;
    gui_mch_exit(rc);
}

/*
 * Set the font. Uses the 'font' option. The first font name that works is
 * used. If none is found, use the default font.
 * Return OK when able to set the font.
 */
    int
gui_init_font(font_list)
    char_u  *font_list;
{
#define FONTLEN 100
    char_u  font_name[FONTLEN];
    int     font_list_empty = FALSE;
    int	    ret = FAIL;

    if (!gui.in_use)
	return FAIL;

    font_name[0] = NUL;
    if (*font_list == NUL)
	font_list_empty = TRUE;
    else
	while (*font_list != NUL)
	{
	    /* Isolate one font name */
	    (void)copy_option_part(&font_list, font_name, FONTLEN, ",");
	    if (gui_mch_init_font(font_name) == OK)
	    {
		ret = OK;
		break;
	    }
	}

    if (ret != OK && STRCMP(font_name, "*") != 0
	    && (font_list_empty || gui.norm_font == (GuiFont)0))
    {
	/*
	 * Couldn't load any font in 'font_list', keep the current font if
	 * there is one.  If 'font_list' is empty, or if there is no current
	 * font, tell gui_mch_init_font() to try to find a font we can load.
	 */
	ret = gui_mch_init_font(NULL);
    }

    if (ret == OK)
    {
	/* Set normal font as current font */
	gui_mch_set_font(gui.norm_font);
	gui_set_winsize(
#ifdef WIN32
		TRUE
#else
		FALSE
#endif
		);
    }

    return ret;
}

    void
gui_set_cursor(row, col)
    int	    row;
    int	    col;
{
    gui.row = row;
    gui.col = col;
}

/*
 * gui_check_screen - check if the cursor is on the screen.
 */
    static void
gui_check_screen()
{
    if (gui.row >= Rows)
	gui.row = Rows - 1;
    if (gui.col >= Columns)
	gui.col = Columns - 1;
    if (gui.cursor_row >= Rows || gui.cursor_col >= Columns)
	gui.cursor_is_valid = FALSE;
}

/*
 * Redraw the cursor if necessary or when forced.
 * Careful: The contents of LinePointers[] must match what is on the screen,
 * otherwise this goes wrong.  May need to call out_flush() first.
 */
    void
gui_update_cursor(force, clear_selection)
    int		force;		/* when TRUE, update even when not moved */
    int		clear_selection;/* clear selection under cursor */
{
    int		cur_width = 0;
    int		cur_height = 0;
    long_u	old_hl_mask;
    int		idx;
    int		id;
    GuiColor	cfg, cbg, cc;	/* cursor fore-/background color */
    int		cattr;		/* cursor attributes */
    int		attr;
    struct attr_entry *aep = NULL;

    gui_check_screen();
    if (!gui.cursor_is_valid || force
		    || gui.row != gui.cursor_row || gui.col != gui.cursor_col)
    {
	gui_undraw_cursor();
	if (gui.row <0)
	    return;
	gui.cursor_row = gui.row;
	gui.cursor_col = gui.col;
	gui.cursor_is_valid = TRUE;

	/* Only write to the screen after LinePointers[] has been initialized */
	if (!screen_cleared || NextScreen == NULL)
	    return;

	/* Clear the selection if we are about to write over it */
	if (clear_selection)
	    clip_may_clear_selection(gui.row, gui.row);
	/* Check that the cursor is inside the window (resizing may have made
	 * it invalid) */
	if (gui.row >= screen_Rows || gui.col >= screen_Columns)
	    return;

	/*
	 * How the cursor is drawn depends on the current mode.
	 */
	idx = get_cursor_idx();
	id = cursor_table[idx].id;

	/* get the colors and attributes for the cursor.  Default is inverted */
	cfg = (GuiColor)-1;
	cbg = (GuiColor)-1;
	cattr = HL_INVERSE;
	gui_mch_set_blinking(cursor_table[idx].blinkwait,
			     cursor_table[idx].blinkon,
			     cursor_table[idx].blinkoff);
	if (id > 0)
	{
	    cattr = syn_id2colors(id, &cfg, &cbg);
	    --cbg;
	    --cfg;
	}

	/*
	 * Get the attributes for the character under the cursor.
	 * When no cursor color was given, use the character color.
	 */
	attr = *(LinePointers[gui.row] + gui.col + screen_Columns);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -