5180 lines · 126.0 KB · C
RawDownload
/* 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. * See README.txt for an overview of the Vim source code. */ #include "vim.h" /* Structure containing all the GUI information */gui_T gui; #if defined(FEAT_MBYTE) && !defined(HAVE_GTK2)static void set_guifontwide __ARGS((char_u *font_name));#endifstatic void gui_check_pos __ARGS((void));static void gui_position_components __ARGS((int));static void gui_outstr __ARGS((char_u *, int));static int gui_screenchar __ARGS((int off, int flags, guicolor_T fg, guicolor_T bg, int back));#ifdef HAVE_GTK2static int gui_screenstr __ARGS((int off, int len, int flags, guicolor_T fg, guicolor_T bg, int back));#endifstatic void gui_delete_lines __ARGS((int row, int count));static void gui_insert_lines __ARGS((int row, int count));static void fill_mouse_coord __ARGS((char_u *p, int col, int row));#if defined(FEAT_GUI_TABLINE) || defined(PROTO)static int gui_has_tabline __ARGS((void));#endifstatic void gui_do_scrollbar __ARGS((win_T *wp, int which, int enable));static colnr_T scroll_line_len __ARGS((linenr_T lnum));static void gui_update_horiz_scrollbar __ARGS((int));static void gui_set_fg_color __ARGS((char_u *name));static void gui_set_bg_color __ARGS((char_u *name));static win_T *xy2win __ARGS((int x, int y)); static int can_update_cursor = TRUE; /* can display the cursor */ /* * 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(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MAC)# define SCROLL_PAST_END#endif /* * gui_start -- Called when user wants to start the GUI. * * Careful: This function can be called recursively when there is a ":gui" * command in the .gvimrc file.  Only the first call should fork, not the * recursive call. */    voidgui_start(){    char_u	*old_term;#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOS_X)# define MAY_FORK    int		dofork = TRUE;#endif    static int	recursive = 0;     old_term = vim_strsave(T_NAME);     /*     * 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 shell 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 shell 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; #ifdef MAY_FORK    if (!gui.dofork || vim_strchr(p_go, GO_FORG) || recursive)	dofork = FALSE;#endif    ++recursive;     termcapinit((char_u *)"builtin_gui");    gui.starting = recursive - 1;     if (!gui.in_use)			/* failed to start GUI */    {	termcapinit(old_term);		/* back to old term settings */	settmode(TMODE_RAW);		/* restart RAW mode */#ifdef FEAT_TITLE	set_title_defaults();		/* set 'title' and 'icon' again */#endif    }     vim_free(old_term); #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)    if (gui.in_use)	/* Display error messages in a dialog now. */	display_errors();#endif #if defined(MAY_FORK) && !defined(__QNXNTO__)    /*     * 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 && dofork)    {	int	pipefd[2];	/* pipe between parent and child */	int	pipe_error;	char	dummy;	pid_t	pid = -1; 	/* Setup a pipe between the child and the parent, so that the parent	 * knows when the child has done the setsid() call and is allowed to	 * exit. */	pipe_error = (pipe(pipefd) < 0);	pid = fork();	if (pid > 0)	    /* Parent */	{	    /* Give the child some time to do the setsid(), otherwise the	     * exit() may kill the child too (when starting gvim from inside a	     * gvim). */	    if (pipe_error)		ui_delay(300L, TRUE);	    else	    {		/* The read returns when the child closes the pipe (or when		 * the child dies for some reason). */		close(pipefd[1]);		(void)read(pipefd[0], &dummy, (size_t)1);		close(pipefd[0]);	    } 	    /* When swapping screens we may need to go to the next line, e.g.,	     * after a hit-enter prompt and using ":gui". */	    if (newline_on_exit)		mch_errmsg("\r\n"); 	    /*	     * The parent must skip the normal exit() processing, the child	     * will do it.  For example, GTK messes up signals when exiting.	     */	    _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	if (!pipe_error)	{	    close(pipefd[0]);	    close(pipefd[1]);	} # if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)	/* Tell the session manager our new PID */	gui_mch_forked();# endif    }#else# if defined(__QNXNTO__)    if (gui.in_use && dofork)	procmgr_daemon(0, PROCMGR_DAEMON_KEEPUMASK | PROCMGR_DAEMON_NOCHDIR |		PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL);# endif#endif #ifdef FEAT_AUTOCMD    /* If the GUI started successfully, trigger the GUIEnter event, otherwise     * the GUIFailed event. */    apply_autocmds(gui.in_use ? EVENT_GUIENTER : EVENT_GUIFAILED,						   NULL, NULL, FALSE, curbuf);#endif     --recursive;} /* * Call this when vim starts up, whether or not the GUI is started */    voidgui_prepare(argc, argv)    int	    *argc;    char    **argv;{    gui.in_use = FALSE;		    /* No GUI yet (maybe later) */    gui.starting = FALSE;	    /* No GUI yet (maybe later) */    gui_mch_prepare(argc, argv);} /* * Try initializing the GUI and check if it can be started. * Used from main() to check early if "vim -g" can start the GUI. * Used from gui_init() to prepare for starting the GUI. * Returns FAIL or OK. */    intgui_init_check(){    static int result = MAYBE;     if (result != MAYBE)    {	if (result == FAIL)	    EMSG(_("E229: Cannot start the GUI"));	return result;    }     gui.shell_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 = 0;    gui.row = 0;    gui.num_cols = Columns;    gui.num_rows = Rows;     gui.cursor_is_valid = FALSE;    gui.scroll_region_top = 0;    gui.scroll_region_bot = Rows - 1;    gui.scroll_region_left = 0;    gui.scroll_region_right = Columns - 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 = NOFONT;#ifndef HAVE_GTK2    gui.bold_font = NOFONT;    gui.ital_font = NOFONT;    gui.boldital_font = NOFONT;# ifdef FEAT_XFONTSET    gui.fontset = NOFONTSET;# endif#endif #ifdef FEAT_MENU# ifndef HAVE_GTK2#  ifdef FONTSET_ALWAYS    gui.menu_fontset = NOFONTSET;#  else    gui.menu_font = NOFONT;#  endif# endif    gui.menu_is_active = TRUE;	    /* default: include menu */# ifndef FEAT_GUI_GTK    gui.menu_height = MENU_DEFAULT_HEIGHT;    gui.menu_width = 0;# endif#endif#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))    gui.toolbar_height = 0;#endif#if defined(FEAT_FOOTER) && defined(FEAT_GUI_MOTIF)    gui.footer_height = 0;#endif#ifdef FEAT_BEVAL_TIP    gui.tooltip_fontset = NOFONTSET;#endif     gui.scrollbar_width = gui.scrollbar_height = SB_DEFAULT_WIDTH;    gui.prev_wrap = -1; #ifdef ALWAYS_USE_GUI    result = OK;#else    result = gui_mch_init_check();#endif    return result;} /* * This is the call which starts the GUI. */    voidgui_init(){    win_T	*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 shell to be opened halfway reading a     * gvimrc file.     */    if (!recursive)    {	++recursive; 	clip_init(TRUE); 	/* If can't initialize, don't try doing the rest */	if (gui_init_check() == FAIL)	{	    --recursive;	    clip_init(FALSE);	    return;	} 	/*	 * Reset 'paste'.  It's useful in the terminal, but not in the GUI.  It	 * breaks the Paste toolbar button.	 */	set_option_value((char_u *)"paste", 0L, NULL, 0); 	/*	 * Set up system-wide default menus.	 */#if defined(SYS_MENU_FILE) && defined(FEAT_MENU)	if (vim_strchr(p_go, GO_NOSYSMENU) == NULL)	{	    sys_menu = TRUE;	    do_source((char_u *)SYS_MENU_FILE, FALSE, DOSO_NONE);	    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", OPT_FREE, SID_NONE); 	/*	 * If -U option given, use only the initializations from that file and	 * nothing else.  Skip all initializations for "-U NONE" or "-u NORC".	 */	if (use_gvimrc != NULL)	{	    if (STRCMP(use_gvimrc, "NONE") != 0		    && STRCMP(use_gvimrc, "NORC") != 0		    && do_source(use_gvimrc, FALSE, DOSO_NONE) != OK)		EMSG2(_("E230: 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, DOSO_NONE);#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 third user gvimrc file ($VIM/.gvimrc for Amiga)	     * The first that exists is used, the rest is ignored.	     */	    if (process_env((char_u *)"GVIMINIT", FALSE) == FAIL		 && do_source((char_u *)USR_GVIMRC_FILE, TRUE,							  DOSO_GVIMRC) == FAIL#ifdef USR_GVIMRC_FILE2		 && do_source((char_u *)USR_GVIMRC_FILE2, TRUE,							  DOSO_GVIMRC) == FAIL#endif				)	    {#ifdef USR_GVIMRC_FILE3		(void)do_source((char_u *)USR_GVIMRC_FILE3, TRUE, DOSO_GVIMRC);#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, USR_GVIMRC_FILE3 or SYS_GVIMRC_FILE.	     */	    if (p_exrc)	    {#ifdef UNIX		{		    struct stat s; 		    /* if ".gvimrc" file is not owned by user, set 'secure'		     * mode */		    if (mch_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#ifdef USR_GVIMRC_FILE3			&& fullpathcmp((char_u *)USR_GVIMRC_FILE3,				     (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME#endif			)		    do_source((char_u *)GVIMRC_FILE, TRUE, DOSO_GVIMRC); 		if (secure == 2)		    need_wait_return = TRUE;		secure = 0;	    }	} 	if (need_wait_return || msg_didany)	    wait_return(TRUE); 	--recursive;    }     /* If recursive call opened the shell, return here from the first call */    if (gui.in_use)	return;     /*     * Create the GUI shell.     */    gui.in_use = TRUE;		/* Must be set after menus have been set up */    if (gui_mch_init() == FAIL)	goto error;     /* Avoid a delay for an error message that was printed in the terminal     * where Vim was started. */    emsg_on_display = FALSE;    msg_scrolled = 0;    clear_sb_text();    need_wait_return = FALSE;    msg_didany = FALSE;     /*     * Check validity of any generic resources that may have been loaded.     */    if (gui.border_width < 0)	gui.border_width = 0;     /*     * Set up the fonts.  First use a font specified with "-fn" or "-font".     */    if (font_argument != NULL)	set_option_value((char_u *)"gfn", 0L, (char_u *)font_argument, 0);    if (#ifdef FEAT_XFONTSET	    (*p_guifontset == NUL	     || gui_init_font(p_guifontset, TRUE) == FAIL) &&#endif	    gui_init_font(*p_guifont == NUL ? hl_get_font_name()						  : p_guifont, FALSE) == FAIL)    {	EMSG(_("E665: Cannot start GUI, no valid font found"));	goto error2;    }#ifdef FEAT_MBYTE    if (gui_get_wide_font() == FAIL)	EMSG(_("E231: 'guifontwide' invalid"));#endif     gui.num_cols = Columns;    gui.num_rows = Rows;    gui_reset_scroll_region();     /* Create initial scrollbars */    FOR_ALL_WINDOWS(wp)

Lines 1–500 of 5180.