changeset 18135:1868ec23360e v8.1.2062

patch 8.1.2062: the mouse code is spread out Commit: https://github.com/vim/vim/commit/b20b9e14ddd8db111e886ad0494e15b955159426 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Sep 21 20:48:04 2019 +0200 patch 8.1.2062: the mouse code is spread out Problem: The mouse code is spread out. Solution: Move all the mouse code to mouse.c. (Yegappan Lakshmanan, closes #4959)
author Bram Moolenaar <Bram@vim.org>
date Sat, 21 Sep 2019 21:00:07 +0200
parents c06a2bc8144f
children ab2c97df5d08
files Filelist src/Make_cyg_ming.mak src/Make_morph.mak src/Make_mvc.mak src/Make_vms.mms src/Makefile src/README.md src/auto/configure src/configure.ac src/edit.c src/ex_cmds.c src/ex_docmd.c src/ex_getln.c src/insexpand.c src/libvterm/src/mouse.c src/libvterm/src/termmouse.c src/main.c src/message.c src/misc1.c src/misc2.c src/mouse.c src/normal.c src/proto.h src/proto/edit.pro src/proto/misc1.pro src/proto/misc2.pro src/proto/mouse.pro src/proto/normal.pro src/proto/term.pro src/proto/ui.pro src/search.c src/term.c src/ui.c src/version.c src/vim.h src/window.c
diffstat 36 files changed, 2513 insertions(+), 2588 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -80,6 +80,7 @@ SRC_ALL =	\
 		src/message_test.c \
 		src/misc1.c \
 		src/misc2.c \
+		src/mouse.c \
 		src/move.c \
 		src/mysign \
 		src/nbdebug.c \
@@ -231,6 +232,7 @@ SRC_ALL =	\
 		src/proto/message.pro \
 		src/proto/misc1.pro \
 		src/proto/misc2.pro \
+		src/proto/mouse.pro \
 		src/proto/move.pro \
 		src/proto/netbeans.pro \
 		src/proto/normal.pro \
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -754,6 +754,7 @@ OBJ = \
 	$(OUTDIR)/message.o \
 	$(OUTDIR)/misc1.o \
 	$(OUTDIR)/misc2.o \
+	$(OUTDIR)/mouse.o \
 	$(OUTDIR)/move.o \
 	$(OUTDIR)/mbyte.o \
 	$(OUTDIR)/normal.o \
@@ -866,7 +867,7 @@ ifeq ($(TERMINAL),yes)
 OBJ += $(OUTDIR)/terminal.o \
 	$(OUTDIR)/encoding.o \
 	$(OUTDIR)/keyboard.o \
-	$(OUTDIR)/mouse.o \
+	$(OUTDIR)/termmouse.o \
 	$(OUTDIR)/parser.o \
 	$(OUTDIR)/pen.o \
 	$(OUTDIR)/termscreen.o \
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -74,6 +74,7 @@ SRC =	arabic.c						\
 	message.c						\
 	misc1.c							\
 	misc2.c							\
+	mouse.c							\
 	move.c							\
 	normal.c						\
 	ops.c							\
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -365,7 +365,7 @@ TERM_OBJ = \
 	$(OBJDIR)/terminal.obj \
 	$(OBJDIR)/encoding.obj \
 	$(OBJDIR)/keyboard.obj \
-	$(OBJDIR)/mouse.obj \
+	$(OBJDIR)/termmouse.obj \
 	$(OBJDIR)/parser.obj \
 	$(OBJDIR)/pen.obj \
 	$(OBJDIR)/termscreen.obj \
@@ -762,6 +762,7 @@ OBJ = \
 	$(OUTDIR)\message.obj \
 	$(OUTDIR)\misc1.obj \
 	$(OUTDIR)\misc2.obj \
+	$(OUTDIR)\mouse.obj \
 	$(OUTDIR)\move.obj \
 	$(OUTDIR)\normal.obj \
 	$(OUTDIR)\ops.obj \
@@ -1601,6 +1602,8 @@ lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).l
 
 $(OUTDIR)/misc2.obj:	$(OUTDIR) misc2.c  $(INCL)
 
+$(OUTDIR)/mouse.obj:	$(OUTDIR) mouse.c  $(INCL)
+
 $(OUTDIR)/move.obj:	$(OUTDIR) move.c  $(INCL)
 
 $(OUTDIR)/mbyte.obj: $(OUTDIR) mbyte.c  $(INCL)
@@ -1736,7 +1739,7 @@ CCCTERM = $(CC) $(CFLAGS) -Ilibvterm/inc
 
 $(OUTDIR)/keyboard.obj: $(OUTDIR) libvterm/src/keyboard.c $(TERM_DEPS)
 
-$(OUTDIR)/mouse.obj: $(OUTDIR) libvterm/src/mouse.c $(TERM_DEPS)
+$(OUTDIR)/termmouse.obj: $(OUTDIR) libvterm/src/termmouse.c $(TERM_DEPS)
 
 $(OUTDIR)/parser.obj: $(OUTDIR) libvterm/src/parser.c $(TERM_DEPS)
 
@@ -1822,6 +1825,7 @@ proto.h: \
 	proto/message.pro \
 	proto/misc1.pro \
 	proto/misc2.pro \
+	proto/mouse.pro \
 	proto/move.pro \
 	proto/mbyte.pro \
 	proto/normal.pro \
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -316,7 +316,8 @@ SRC =	arabic.c arglist.c autocmd.c beval
 	if_cscope.c if_xcmdsrv.c fileio.c filepath.c, findfile.c fold.c \
 	getchar.c hardcopy.c hashtab.c highlight.c \
 	indent.c insexpand.c json.c list.c main.c map.c mark.c menu.c mbyte.c \
-	memfile.c memline.c message.c misc1.c misc2.c move.c normal.c ops.c \
+	memfile.c memline.c message.c misc1.c misc2.c mouse.c move.c normal.c \
+	ops.c \
 	option.c optionstr.c popupmnu.c popupwin.c profiler.c quickfix.c \
 	regexp.c scriptfile.c \
 	search.c session.c sha256.c sign.c spell.c spellfile.c syntax.c tag.c \
@@ -336,7 +337,8 @@ OBJ = 	arabic.obj arglist.obj autocmd.ob
 	findfile.obj fold.obj getchar.obj hardcopy.obj hashtab.obj \
 	highlight.obj indent.obj insexpand.obj json.obj list.obj main.obj \
 	map.obj mark.obj menu.obj memfile.obj memline.obj message.obj \
-	misc1.obj misc2.obj move.obj mbyte.obj normal.obj ops.obj option.obj \
+	misc1.obj misc2.obj mouse.obj move.obj mbyte.obj normal.obj ops.obj \
+	option.obj \
 	optionstr.obj popupmnu.obj popupwin.obj profiler.obj quickfix.obj \
 	regexp.obj scriptfile.obj \
 	search.obj session.obj sha256.obj sign.obj spell.obj spellfile.obj \
@@ -697,6 +699,9 @@ misc1.obj : misc1.c vim.h [.auto]config.
 misc2.obj : misc2.c vim.h [.auto]config.h feature.h os_unix.h   \
  ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
  [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
+mouse.obj : mouse.c vim.h [.auto]config.h feature.h os_unix.h   \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
 move.obj : move.c vim.h [.auto]config.h feature.h os_unix.h   \
  ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
  [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
--- a/src/Makefile
+++ b/src/Makefile
@@ -1629,6 +1629,7 @@ BASIC_SRC = \
 	message.c \
 	misc1.c \
 	misc2.c \
+	mouse.c \
 	move.c \
 	mbyte.c \
 	normal.c \
@@ -1762,6 +1763,7 @@ OBJ_COMMON = \
 	objects/menu.o \
 	objects/misc1.o \
 	objects/misc2.o \
+	objects/mouse.o \
 	objects/move.o \
 	objects/mbyte.o \
 	objects/normal.o \
@@ -1921,6 +1923,7 @@ PRO_AUTO = \
 	message.pro \
 	misc1.pro \
 	misc2.pro \
+	mouse.pro \
 	move.pro \
 	normal.pro \
 	ops.pro \
@@ -3287,6 +3290,9 @@ objects/misc1.o: misc1.c
 objects/misc2.o: misc2.c
 	$(CCC) -o $@ misc2.c
 
+objects/mouse.o: mouse.c
+	$(CCC) -o $@ mouse.c
+
 objects/move.o: move.c
 	$(CCC) -o $@ move.c
 
@@ -3430,8 +3436,8 @@ objects/encoding.o: libvterm/src/encodin
 objects/keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS)
 	$(CCCTERM) -o $@ libvterm/src/keyboard.c
 
-objects/mouse.o: libvterm/src/mouse.c $(TERM_DEPS)
-	$(CCCTERM) -o $@ libvterm/src/mouse.c
+objects/termmouse.o: libvterm/src/termmouse.c $(TERM_DEPS)
+	$(CCCTERM) -o $@ libvterm/src/termmouse.c
 
 objects/parser.o: libvterm/src/parser.c $(TERM_DEPS)
 	$(CCCTERM) -o $@ libvterm/src/parser.c
@@ -3769,6 +3775,10 @@ objects/misc2.o: misc2.c vim.h protodef.
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
  proto.h globals.h
+objects/mouse.o: mouse.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h
 objects/move.o: move.c vim.h protodef.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
@@ -4063,7 +4073,7 @@ objects/encoding.o: libvterm/src/encodin
 objects/keyboard.o: libvterm/src/keyboard.c libvterm/src/vterm_internal.h \
  libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
  libvterm/src/utf8.h
-objects/mouse.o: libvterm/src/mouse.c libvterm/src/vterm_internal.h \
+objects/termmouse.o: libvterm/src/termmouse.c libvterm/src/vterm_internal.h \
  libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
  libvterm/src/utf8.h
 objects/parser.o: libvterm/src/parser.c libvterm/src/vterm_internal.h \
--- a/src/README.md
+++ b/src/README.md
@@ -54,6 +54,7 @@ memfile.c	| storing lines for buffers in
 memline.c	| storing lines for buffers in memory
 menu.c		| menus
 message.c	| (error) messages
+mouse.c		| handling the mouse
 ops.c		| handling operators ("d", "y", "p")
 option.c	| options
 optionstr.c	| handling string options
@@ -63,7 +64,7 @@ profiler.c	| vim script profiler
 quickfix.c	| quickfix commands (":make", ":cn")
 regexp.c	| pattern matching
 scriptfile.c	| runtime directory handling and sourcing scripts
-screen.c	| updating the windows
+screen.c	| lower level screen functions
 search.c	| pattern searching
 session.c	| sessions and views
 sign.c		| signs
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -7909,7 +7909,7 @@ if test "$enable_terminal" = "yes" -a "$
 
   TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/termscreen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
 
-  TERM_OBJ="objects/encoding.o objects/keyboard.o objects/mouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
+  TERM_OBJ="objects/encoding.o objects/keyboard.o objects/termmouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
 
 fi
 
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -2106,7 +2106,7 @@ if test "$enable_terminal" = "yes" -a "$
   AC_DEFINE(FEAT_TERMINAL)
   TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/termscreen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
   AC_SUBST(TERM_SRC)
-  TERM_OBJ="objects/encoding.o objects/keyboard.o objects/mouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
+  TERM_OBJ="objects/encoding.o objects/keyboard.o objects/termmouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
   AC_SUBST(TERM_OBJ)
 fi
 
--- a/src/edit.c
+++ b/src/edit.c
@@ -27,7 +27,6 @@ static void ins_ctrl_v(void);
 #ifdef FEAT_JOB_CHANNEL
 static void init_prompt(int cmdchar_todo);
 #endif
-static void undisplay_dollar(void);
 static void insert_special(int, int, int);
 static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c);
 static void check_auto_format(int);
@@ -56,10 +55,6 @@ static void ins_ctrl_o(void);
 static void ins_shift(int c, int lastc);
 static void ins_del(void);
 static int  ins_bs(int c, int mode, int *inserted_space_p);
-#ifdef FEAT_MOUSE
-static void ins_mouse(int c);
-static void ins_mousescroll(int dir);
-#endif
 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
 static void ins_tabline(int c);
 #endif
@@ -322,9 +317,7 @@ edit(
     im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
 #endif
 
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 #ifdef FEAT_CMDL_INFO
     clear_showcmd();
 #endif
@@ -1759,7 +1752,7 @@ display_dollar(colnr_T col)
  * Call this function before moving the cursor from the normal insert position
  * in insert mode.
  */
-    static void
+    void
 undisplay_dollar(void)
 {
     if (dollar_vcol >= 0)
@@ -4508,9 +4501,7 @@ ins_esc(
     /* need to position cursor again (e.g. when on a TAB ) */
     changed_cline_bef_curs();
 
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 #ifdef CURSOR_SHAPE
     ui_cursor_shape();		/* may show different cursor shape */
 #endif
@@ -5157,134 +5148,6 @@ ins_bs(
     return did_backspace;
 }
 
-#ifdef FEAT_MOUSE
-    static void
-ins_mouse(int c)
-{
-    pos_T	tpos;
-    win_T	*old_curwin = curwin;
-
-# ifdef FEAT_GUI
-    /* When GUI is active, also move/paste when 'mouse' is empty */
-    if (!gui.in_use)
-# endif
-	if (!mouse_has(MOUSE_INSERT))
-	    return;
-
-    undisplay_dollar();
-    tpos = curwin->w_cursor;
-    if (do_mouse(NULL, c, BACKWARD, 1L, 0))
-    {
-	win_T	*new_curwin = curwin;
-
-	if (curwin != old_curwin && win_valid(old_curwin))
-	{
-	    /* Mouse took us to another window.  We need to go back to the
-	     * previous one to stop insert there properly. */
-	    curwin = old_curwin;
-	    curbuf = curwin->w_buffer;
-#ifdef FEAT_JOB_CHANNEL
-	    if (bt_prompt(curbuf))
-		// Restart Insert mode when re-entering the prompt buffer.
-		curbuf->b_prompt_insert = 'A';
-#endif
-	}
-	start_arrow(curwin == old_curwin ? &tpos : NULL);
-	if (curwin != new_curwin && win_valid(new_curwin))
-	{
-	    curwin = new_curwin;
-	    curbuf = curwin->w_buffer;
-	}
-# ifdef FEAT_CINDENT
-	can_cindent = TRUE;
-# endif
-    }
-
-    /* redraw status lines (in case another window became active) */
-    redraw_statuslines();
-}
-
-    static void
-ins_mousescroll(int dir)
-{
-    pos_T	tpos;
-    win_T	*old_curwin = curwin, *wp;
-    int		did_scroll = FALSE;
-
-    tpos = curwin->w_cursor;
-
-    if (mouse_row >= 0 && mouse_col >= 0)
-    {
-	int row, col;
-
-	row = mouse_row;
-	col = mouse_col;
-
-	/* find the window at the pointer coordinates */
-	wp = mouse_find_win(&row, &col, FIND_POPUP);
-	if (wp == NULL)
-	    return;
-	curwin = wp;
-	curbuf = curwin->w_buffer;
-    }
-    if (curwin == old_curwin)
-	undisplay_dollar();
-
-    /* Don't scroll the window in which completion is being done. */
-    if (!pum_visible() || curwin != old_curwin)
-    {
-	if (dir == MSCR_DOWN || dir == MSCR_UP)
-	{
-	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-		scroll_redraw(dir,
-			(long)(curwin->w_botline - curwin->w_topline));
-	    else
-		scroll_redraw(dir, 3L);
-# ifdef FEAT_TEXT_PROP
-	if (WIN_IS_POPUP(curwin))
-	    popup_set_firstline(curwin);
-# endif
-	}
-#ifdef FEAT_GUI
-	else
-	{
-	    int val, step = 6;
-
-	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-		step = curwin->w_width;
-	    val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step);
-	    if (val < 0)
-		val = 0;
-	    gui_do_horiz_scroll(val, TRUE);
-	}
-#endif
-	did_scroll = TRUE;
-    }
-
-    curwin->w_redr_status = TRUE;
-
-    curwin = old_curwin;
-    curbuf = curwin->w_buffer;
-
-    /* The popup menu may overlay the window, need to redraw it.
-     * TODO: Would be more efficient to only redraw the windows that are
-     * overlapped by the popup menu. */
-    if (pum_visible() && did_scroll)
-    {
-	redraw_all_later(NOT_VALID);
-	ins_compl_show_pum();
-    }
-
-    if (!EQUAL_POS(curwin->w_cursor, tpos))
-    {
-	start_arrow(&tpos);
-# ifdef FEAT_CINDENT
-	can_cindent = TRUE;
-# endif
-    }
-}
-#endif
-
 /*
  * Handle receiving P_PS: start paste mode.  Inserts the following text up to
  * P_PE literally.
@@ -6401,10 +6264,16 @@ do_insert_char_pre(int c)
 
 #if defined(FEAT_CINDENT) || defined(PROTO)
     int
-can_cindent_get(void)
+get_can_cindent(void)
 {
     return can_cindent;
 }
+
+    void
+set_can_cindent(int val)
+{
+    can_cindent = val;
+}
 #endif
 
 /*
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -4221,9 +4221,7 @@ do_sub(exarg_T *eap)
 		     * properly */
 		    save_State = State;
 		    State = CONFIRM;
-#ifdef FEAT_MOUSE
-		    setmouse();		/* disable mouse in xterm */
-#endif
+		    setmouse();		// disable mouse in xterm
 		    curwin->w_cursor.col = regmatch.startpos[0].col;
 		    if (curwin->w_p_crb)
 			do_check_cursorbind();
@@ -4397,9 +4395,7 @@ do_sub(exarg_T *eap)
 			    scrolldown_clamp();
 		    }
 		    State = save_State;
-#ifdef FEAT_MOUSE
 		    setmouse();
-#endif
 		    if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
 			--no_u_sync;
 
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -7578,9 +7578,7 @@ ex_normal(exarg_T *eap)
 
     restore_current_state(&save_state);
     --ex_normal_busy;
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 #ifdef CURSOR_SHAPE
     ui_cursor_shape();		/* may show different cursor shape */
 #endif
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -924,9 +924,7 @@ getcmdline_int(
 	im_set_active(TRUE);
 #endif
 
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 #ifdef CURSOR_SHAPE
     ui_cursor_shape();		/* may show different cursor shape */
 #endif
@@ -2389,9 +2387,7 @@ returncmd:
 	im_save_status(b_im_ptr);
     im_set_active(FALSE);
 #endif
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 #ifdef CURSOR_SHAPE
     ui_cursor_shape();		/* may show different cursor shape */
 #endif
@@ -4160,9 +4156,7 @@ open_cmdwin(void)
     exmode_active = 0;
 
     State = NORMAL;
-# ifdef FEAT_MOUSE
     setmouse();
-# endif
 
     // Trigger CmdwinEnter autocommands.
     trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINENTER);
@@ -4290,9 +4284,7 @@ open_cmdwin(void)
 # endif
 
     State = save_State;
-# ifdef FEAT_MOUSE
     setmouse();
-# endif
 
     return cmdwin_result;
 }
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -1995,7 +1995,7 @@ ins_compl_prep(int c)
 	    }
 
 #ifdef FEAT_CINDENT
-	    want_cindent = (can_cindent_get() && cindent_on());
+	    want_cindent = (get_can_cindent() && cindent_on());
 #endif
 	    // When completing whole lines: fix indent for 'cindent'.
 	    // Otherwise, break line if it's too long.
rename from src/libvterm/src/mouse.c
rename to src/libvterm/src/termmouse.c
--- a/src/main.c
+++ b/src/main.c
@@ -684,9 +684,7 @@ vim_main2(void)
     starttermcap();	    /* start termcap if not done by wait_return() */
     TIME_MSG("start termcap");
 
-#ifdef FEAT_MOUSE
-    setmouse();				/* may start using the mouse */
-#endif
+    setmouse();				// may start using the mouse
     if (scroll_region)
 	scroll_region_reset();		/* In case Rows changed */
     scroll_start();	/* may scroll the screen to the right position */
@@ -1182,9 +1180,7 @@ main_loop(
 	emsg_skip = 0;
 # endif
 	emsg_off = 0;
-# ifdef FEAT_MOUSE
 	setmouse();
-# endif
 	settmode(TMODE_RAW);
 	starttermcap();
 	scroll_start();
--- a/src/message.c
+++ b/src/message.c
@@ -1058,9 +1058,7 @@ wait_return(int redraw)
 	screenalloc(FALSE);
 
 	State = HITRETURN;
-#ifdef FEAT_MOUSE
 	setmouse();
-#endif
 #ifdef USE_ON_FLY_SCROLL
 	dont_scroll = TRUE;		/* disallow scrolling here */
 #endif
@@ -1216,9 +1214,7 @@ wait_return(int redraw)
      */
     tmpState = State;
     State = oldState;		    /* restore State before set_shellsize */
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
     msg_check();
 
 #if defined(UNIX) || defined(VMS)
@@ -2684,9 +2680,7 @@ do_more_prompt(int typed_char)
     }
 
     State = ASKMORE;
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
     if (typed_char == NUL)
 	msg_moremsg(FALSE);
     for (;;)
@@ -2902,9 +2896,7 @@ do_more_prompt(int typed_char)
     /* clear the --more-- message */
     screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
     State = oldState;
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
     if (quit_more)
     {
 	msg_row = Rows - 1;
@@ -3608,9 +3600,7 @@ do_dialog(
 
     oldState = State;
     State = CONFIRM;
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 
     /*
      * Since we wait for a keypress, don't make the
@@ -3673,9 +3663,7 @@ do_dialog(
     }
 
     State = oldState;
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
     --no_wait_return;
     msg_end_prompt();
 
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -1148,14 +1148,12 @@ ask_yesno(char_u *str, int direct)
 	settmode(TMODE_RAW);
     ++no_wait_return;
 #ifdef USE_ON_FLY_SCROLL
-    dont_scroll = TRUE;		/* disallow scrolling here */
+    dont_scroll = TRUE;		// disallow scrolling here
 #endif
-    State = CONFIRM;		/* mouse behaves like with :confirm */
-#ifdef FEAT_MOUSE
-    setmouse();			/* disables mouse for xterm */
-#endif
+    State = CONFIRM;		// mouse behaves like with :confirm
+    setmouse();			// disables mouse for xterm
     ++no_mapping;
-    ++allow_keys;		/* no mapping here, but recognize keys */
+    ++allow_keys;		// no mapping here, but recognize keys
 
     while (r != 'y' && r != 'n')
     {
@@ -1172,47 +1170,13 @@ ask_yesno(char_u *str, int direct)
     }
     --no_wait_return;
     State = save_State;
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
     --no_mapping;
     --allow_keys;
 
     return r;
 }
 
-#if defined(FEAT_MOUSE) || defined(PROTO)
-/*
- * Return TRUE if "c" is a mouse key.
- */
-    int
-is_mouse_key(int c)
-{
-    return c == K_LEFTMOUSE
-	|| c == K_LEFTMOUSE_NM
-	|| c == K_LEFTDRAG
-	|| c == K_LEFTRELEASE
-	|| c == K_LEFTRELEASE_NM
-	|| c == K_MOUSEMOVE
-	|| c == K_MIDDLEMOUSE
-	|| c == K_MIDDLEDRAG
-	|| c == K_MIDDLERELEASE
-	|| c == K_RIGHTMOUSE
-	|| c == K_RIGHTDRAG
-	|| c == K_RIGHTRELEASE
-	|| c == K_MOUSEDOWN
-	|| c == K_MOUSEUP
-	|| c == K_MOUSELEFT
-	|| c == K_MOUSERIGHT
-	|| c == K_X1MOUSE
-	|| c == K_X1DRAG
-	|| c == K_X1RELEASE
-	|| c == K_X2MOUSE
-	|| c == K_X2DRAG
-	|| c == K_X2RELEASE;
-}
-#endif
-
 #if defined(FEAT_EVAL) || defined(PROTO)
 
 /*
@@ -1340,6 +1304,8 @@ f_state(typval_T *argvars, typval_T *ret
     if (channel_in_blocking_wait())
 	may_add_state_char(&ga, include, 'w');
 # endif
+    if (!get_was_safe_state())
+	may_add_state_char(&ga, include, 'S');
     for (i = 0; i < get_callback_depth() && i < 3; ++i)
 	may_add_state_char(&ga, include, 'c');
     if (msg_scrolled > 0)
@@ -1572,10 +1538,8 @@ prompt_for_number(int *mouse_used)
     cmdline_row = 0;
     save_State = State;
     State = CMDLINE;
-#ifdef FEAT_MOUSE
     // May show different mouse shape.
     setmouse();
-#endif
 
     i = get_number(TRUE, mouse_used);
     if (KeyTyped)
@@ -1590,10 +1554,8 @@ prompt_for_number(int *mouse_used)
     else
 	cmdline_row = save_cmdline_row;
     State = save_State;
-#ifdef FEAT_MOUSE
     // May need to restore mouse shape.
     setmouse();
-#endif
 
     return i;
 }
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -2491,44 +2491,6 @@ static struct key_name_entry
 
 #define KEY_NAMES_TABLE_LEN (sizeof(key_names_table) / sizeof(struct key_name_entry))
 
-#ifdef FEAT_MOUSE
-static struct mousetable
-{
-    int	    pseudo_code;	/* Code for pseudo mouse event */
-    int	    button;		/* Which mouse button is it? */
-    int	    is_click;		/* Is it a mouse button click event? */
-    int	    is_drag;		/* Is it a mouse drag event? */
-} mouse_table[] =
-{
-    {(int)KE_LEFTMOUSE,		MOUSE_LEFT,	TRUE,	FALSE},
-#ifdef FEAT_GUI
-    {(int)KE_LEFTMOUSE_NM,	MOUSE_LEFT,	TRUE,	FALSE},
-#endif
-    {(int)KE_LEFTDRAG,		MOUSE_LEFT,	FALSE,	TRUE},
-    {(int)KE_LEFTRELEASE,	MOUSE_LEFT,	FALSE,	FALSE},
-#ifdef FEAT_GUI
-    {(int)KE_LEFTRELEASE_NM,	MOUSE_LEFT,	FALSE,	FALSE},
-#endif
-    {(int)KE_MIDDLEMOUSE,	MOUSE_MIDDLE,	TRUE,	FALSE},
-    {(int)KE_MIDDLEDRAG,	MOUSE_MIDDLE,	FALSE,	TRUE},
-    {(int)KE_MIDDLERELEASE,	MOUSE_MIDDLE,	FALSE,	FALSE},
-    {(int)KE_RIGHTMOUSE,	MOUSE_RIGHT,	TRUE,	FALSE},
-    {(int)KE_RIGHTDRAG,		MOUSE_RIGHT,	FALSE,	TRUE},
-    {(int)KE_RIGHTRELEASE,	MOUSE_RIGHT,	FALSE,	FALSE},
-    {(int)KE_X1MOUSE,		MOUSE_X1,	TRUE,	FALSE},
-    {(int)KE_X1DRAG,		MOUSE_X1,	FALSE,	TRUE},
-    {(int)KE_X1RELEASE,		MOUSE_X1,	FALSE,	FALSE},
-    {(int)KE_X2MOUSE,		MOUSE_X2,	TRUE,	FALSE},
-    {(int)KE_X2DRAG,		MOUSE_X2,	FALSE,	TRUE},
-    {(int)KE_X2RELEASE,		MOUSE_X2,	FALSE,	FALSE},
-    /* DRAG without CLICK */
-    {(int)KE_MOUSEMOVE,		MOUSE_RELEASE,	FALSE,	TRUE},
-    /* RELEASE without CLICK */
-    {(int)KE_IGNORE,		MOUSE_RELEASE,	FALSE,	FALSE},
-    {0,				0,		0,	0},
-};
-#endif /* FEAT_MOUSE */
-
 /*
  * Return the modifier mask bit (MOD_MASK_*) which corresponds to the given
  * modifier name ('S' for Shift, 'C' for Ctrl etc).
@@ -3050,66 +3012,6 @@ get_key_name(int i)
     return  key_names_table[i].name;
 }
 
-#if defined(FEAT_MOUSE) || defined(PROTO)
-/*
- * Look up the given mouse code to return the relevant information in the other
- * arguments.  Return which button is down or was released.
- */
-    int
-get_mouse_button(int code, int *is_click, int *is_drag)
-{
-    int	    i;
-
-    for (i = 0; mouse_table[i].pseudo_code; i++)
-	if (code == mouse_table[i].pseudo_code)
-	{
-	    *is_click = mouse_table[i].is_click;
-	    *is_drag = mouse_table[i].is_drag;
-	    return mouse_table[i].button;
-	}
-    return 0;	    /* Shouldn't get here */
-}
-
-/*
- * Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
- * the given information about which mouse button is down, and whether the
- * mouse was clicked, dragged or released.
- */
-    int
-get_pseudo_mouse_code(
-    int	    button,	/* eg MOUSE_LEFT */
-    int	    is_click,
-    int	    is_drag)
-{
-    int	    i;
-
-    for (i = 0; mouse_table[i].pseudo_code; i++)
-	if (button == mouse_table[i].button
-	    && is_click == mouse_table[i].is_click
-	    && is_drag == mouse_table[i].is_drag)
-	{
-#ifdef FEAT_GUI
-	    /* Trick: a non mappable left click and release has mouse_col -1
-	     * or added MOUSE_COLOFF.  Used for 'mousefocus' in
-	     * gui_mouse_moved() */
-	    if (mouse_col < 0 || mouse_col > MOUSE_COLOFF)
-	    {
-		if (mouse_col < 0)
-		    mouse_col = 0;
-		else
-		    mouse_col -= MOUSE_COLOFF;
-		if (mouse_table[i].pseudo_code == (int)KE_LEFTMOUSE)
-		    return (int)KE_LEFTMOUSE_NM;
-		if (mouse_table[i].pseudo_code == (int)KE_LEFTRELEASE)
-		    return (int)KE_LEFTRELEASE_NM;
-	    }
-#endif
-	    return mouse_table[i].pseudo_code;
-	}
-    return (int)KE_IGNORE;	    /* not recognized, ignore it */
-}
-#endif /* FEAT_MOUSE */
-
 /*
  * Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
  */
new file mode 100644
--- /dev/null
+++ b/src/mouse.c
@@ -0,0 +1,2314 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved	by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * mouse.c: mouse handling functions
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+
+static int	get_fpos_of_mouse(pos_T *mpos);
+
+/*
+ * Get class of a character for selection: same class means same word.
+ * 0: blank
+ * 1: punctuation groups
+ * 2: normal word character
+ * >2: multi-byte word character.
+ */
+    static int
+get_mouse_class(char_u *p)
+{
+    int		c;
+
+    if (has_mbyte && MB_BYTE2LEN(p[0]) > 1)
+	return mb_get_class(p);
+
+    c = *p;
+    if (c == ' ' || c == '\t')
+	return 0;
+
+    if (vim_iswordc(c))
+	return 2;
+
+    // There are a few special cases where we want certain combinations of
+    // characters to be considered as a single word.  These are things like
+    // "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
+    // character is in its own class.
+    if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
+	return 1;
+    return c;
+}
+
+/*
+ * Move "pos" back to the start of the word it's in.
+ */
+    static void
+find_start_of_word(pos_T *pos)
+{
+    char_u	*line;
+    int		cclass;
+    int		col;
+
+    line = ml_get(pos->lnum);
+    cclass = get_mouse_class(line + pos->col);
+
+    while (pos->col > 0)
+    {
+	col = pos->col - 1;
+	col -= (*mb_head_off)(line, line + col);
+	if (get_mouse_class(line + col) != cclass)
+	    break;
+	pos->col = col;
+    }
+}
+
+/*
+ * Move "pos" forward to the end of the word it's in.
+ * When 'selection' is "exclusive", the position is just after the word.
+ */
+    static void
+find_end_of_word(pos_T *pos)
+{
+    char_u	*line;
+    int		cclass;
+    int		col;
+
+    line = ml_get(pos->lnum);
+    if (*p_sel == 'e' && pos->col > 0)
+    {
+	--pos->col;
+	pos->col -= (*mb_head_off)(line, line + pos->col);
+    }
+    cclass = get_mouse_class(line + pos->col);
+    while (line[pos->col] != NUL)
+    {
+	col = pos->col + (*mb_ptr2len)(line + pos->col);
+	if (get_mouse_class(line + col) != cclass)
+	{
+	    if (*p_sel == 'e')
+		pos->col = col;
+	    break;
+	}
+	pos->col = col;
+    }
+}
+
+/*
+ * Do the appropriate action for the current mouse click in the current mode.
+ * Not used for Command-line mode.
+ *
+ * Normal and Visual Mode:
+ * event	 modi-	position      visual	   change   action
+ *		 fier	cursor			   window
+ * left press	  -	yes	    end		    yes
+ * left press	  C	yes	    end		    yes	    "^]" (2)
+ * left press	  S	yes	end (popup: extend) yes	    "*" (2)
+ * left drag	  -	yes	start if moved	    no
+ * left relse	  -	yes	start if moved	    no
+ * middle press	  -	yes	 if not active	    no	    put register
+ * middle press	  -	yes	 if active	    no	    yank and put
+ * right press	  -	yes	start or extend	    yes
+ * right press	  S	yes	no change	    yes	    "#" (2)
+ * right drag	  -	yes	extend		    no
+ * right relse	  -	yes	extend		    no
+ *
+ * Insert or Replace Mode:
+ * event	 modi-	position      visual	   change   action
+ *		 fier	cursor			   window
+ * left press	  -	yes	(cannot be active)  yes
+ * left press	  C	yes	(cannot be active)  yes	    "CTRL-O^]" (2)
+ * left press	  S	yes	(cannot be active)  yes	    "CTRL-O*" (2)
+ * left drag	  -	yes	start or extend (1) no	    CTRL-O (1)
+ * left relse	  -	yes	start or extend (1) no	    CTRL-O (1)
+ * middle press	  -	no	(cannot be active)  no	    put register
+ * right press	  -	yes	start or extend	    yes	    CTRL-O
+ * right press	  S	yes	(cannot be active)  yes	    "CTRL-O#" (2)
+ *
+ * (1) only if mouse pointer moved since press
+ * (2) only if click is in same buffer
+ *
+ * Return TRUE if start_arrow() should be called for edit mode.
+ */
+    int
+do_mouse(
+    oparg_T	*oap,		// operator argument, can be NULL
+    int		c,		// K_LEFTMOUSE, etc
+    int		dir,		// Direction to 'put' if necessary
+    long	count,
+    int		fixindent)	// PUT_FIXINDENT if fixing indent necessary
+{
+    static int	do_always = FALSE;	// ignore 'mouse' setting next time
+    static int	got_click = FALSE;	// got a click some time back
+
+    int		which_button;	// MOUSE_LEFT, _MIDDLE or _RIGHT
+    int		is_click = FALSE; // If FALSE it's a drag or release event
+    int		is_drag = FALSE;  // If TRUE it's a drag event
+    int		jump_flags = 0;	// flags for jump_to_mouse()
+    pos_T	start_visual;
+    int		moved;		// Has cursor moved?
+    int		in_status_line;	// mouse in status line
+    static int	in_tab_line = FALSE; // mouse clicked in tab line
+    int		in_sep_line;	// mouse in vertical separator line
+    int		c1, c2;
+#if defined(FEAT_FOLDING)
+    pos_T	save_cursor;
+#endif
+    win_T	*old_curwin = curwin;
+    static pos_T orig_cursor;
+    colnr_T	leftcol, rightcol;
+    pos_T	end_visual;
+    int		diff;
+    int		old_active = VIsual_active;
+    int		old_mode = VIsual_mode;
+    int		regname;
+
+#if defined(FEAT_FOLDING)
+    save_cursor = curwin->w_cursor;
+#endif
+
+    // When GUI is active, always recognize mouse events, otherwise:
+    // - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
+    // - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
+    // - For command line and insert mode 'mouse' is checked before calling
+    //	 do_mouse().
+    if (do_always)
+	do_always = FALSE;
+    else
+#ifdef FEAT_GUI
+	if (!gui.in_use)
+#endif
+	{
+	    if (VIsual_active)
+	    {
+		if (!mouse_has(MOUSE_VISUAL))
+		    return FALSE;
+	    }
+	    else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
+		return FALSE;
+	}
+
+    for (;;)
+    {
+	which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
+	if (is_drag)
+	{
+	    // If the next character is the same mouse event then use that
+	    // one. Speeds up dragging the status line.
+	    if (vpeekc() != NUL)
+	    {
+		int nc;
+		int save_mouse_row = mouse_row;
+		int save_mouse_col = mouse_col;
+
+		// Need to get the character, peeking doesn't get the actual
+		// one.
+		nc = safe_vgetc();
+		if (c == nc)
+		    continue;
+		vungetc(nc);
+		mouse_row = save_mouse_row;
+		mouse_col = save_mouse_col;
+	    }
+	}
+	break;
+    }
+
+    if (c == K_MOUSEMOVE)
+    {
+	// Mouse moved without a button pressed.
+#ifdef FEAT_BEVAL_TERM
+	ui_may_remove_balloon();
+	if (p_bevalterm)
+	{
+	    profile_setlimit(p_bdlay, &bevalexpr_due);
+	    bevalexpr_due_set = TRUE;
+	}
+#endif
+#ifdef FEAT_TEXT_PROP
+	popup_handle_mouse_moved();
+#endif
+	return FALSE;
+    }
+
+#ifdef FEAT_MOUSESHAPE
+    // May have stopped dragging the status or separator line.  The pointer is
+    // most likely still on the status or separator line.
+    if (!is_drag && drag_status_line)
+    {
+	drag_status_line = FALSE;
+	update_mouseshape(SHAPE_IDX_STATUS);
+    }
+    if (!is_drag && drag_sep_line)
+    {
+	drag_sep_line = FALSE;
+	update_mouseshape(SHAPE_IDX_VSEP);
+    }
+#endif
+
+    // Ignore drag and release events if we didn't get a click.
+    if (is_click)
+	got_click = TRUE;
+    else
+    {
+	if (!got_click)			// didn't get click, ignore
+	    return FALSE;
+	if (!is_drag)			// release, reset got_click
+	{
+	    got_click = FALSE;
+	    if (in_tab_line)
+	    {
+		in_tab_line = FALSE;
+		return FALSE;
+	    }
+	}
+    }
+
+    // CTRL right mouse button does CTRL-T
+    if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
+    {
+	if (State & INSERT)
+	    stuffcharReadbuff(Ctrl_O);
+	if (count > 1)
+	    stuffnumReadbuff(count);
+	stuffcharReadbuff(Ctrl_T);
+	got_click = FALSE;		// ignore drag&release now
+	return FALSE;
+    }
+
+    // CTRL only works with left mouse button
+    if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
+	return FALSE;
+
+    // When a modifier is down, ignore drag and release events, as well as
+    // multiple clicks and the middle mouse button.
+    // Accept shift-leftmouse drags when 'mousemodel' is "popup.*".
+    if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT
+							     | MOD_MASK_META))
+	    && (!is_click
+		|| (mod_mask & MOD_MASK_MULTI_CLICK)
+		|| which_button == MOUSE_MIDDLE)
+	    && !((mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))
+		&& mouse_model_popup()
+		&& which_button == MOUSE_LEFT)
+	    && !((mod_mask & MOD_MASK_ALT)
+		&& !mouse_model_popup()
+		&& which_button == MOUSE_RIGHT)
+	    )
+	return FALSE;
+
+    // If the button press was used as the movement command for an operator
+    // (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
+    // drag/release events.
+    if (!is_click && which_button == MOUSE_MIDDLE)
+	return FALSE;
+
+    if (oap != NULL)
+	regname = oap->regname;
+    else
+	regname = 0;
+
+    // Middle mouse button does a 'put' of the selected text
+    if (which_button == MOUSE_MIDDLE)
+    {
+	if (State == NORMAL)
+	{
+	    // If an operator was pending, we don't know what the user wanted
+	    // to do. Go back to normal mode: Clear the operator and beep().
+	    if (oap != NULL && oap->op_type != OP_NOP)
+	    {
+		clearopbeep(oap);
+		return FALSE;
+	    }
+
+	    // If visual was active, yank the highlighted text and put it
+	    // before the mouse pointer position.
+	    // In Select mode replace the highlighted text with the clipboard.
+	    if (VIsual_active)
+	    {
+		if (VIsual_select)
+		{
+		    stuffcharReadbuff(Ctrl_G);
+		    stuffReadbuff((char_u *)"\"+p");
+		}
+		else
+		{
+		    stuffcharReadbuff('y');
+		    stuffcharReadbuff(K_MIDDLEMOUSE);
+		}
+		do_always = TRUE;	// ignore 'mouse' setting next time
+		return FALSE;
+	    }
+	    // The rest is below jump_to_mouse()
+	}
+
+	else if ((State & INSERT) == 0)
+	    return FALSE;
+
+	// Middle click in insert mode doesn't move the mouse, just insert the
+	// contents of a register.  '.' register is special, can't insert that
+	// with do_put().
+	// Also paste at the cursor if the current mode isn't in 'mouse' (only
+	// happens for the GUI).
+	if ((State & INSERT) || !mouse_has(MOUSE_NORMAL))
+	{
+	    if (regname == '.')
+		insert_reg(regname, TRUE);
+	    else
+	    {
+#ifdef FEAT_CLIPBOARD
+		if (clip_star.available && regname == 0)
+		    regname = '*';
+#endif
+		if ((State & REPLACE_FLAG) && !yank_register_mline(regname))
+		    insert_reg(regname, TRUE);
+		else
+		{
+		    do_put(regname, BACKWARD, 1L, fixindent | PUT_CURSEND);
+
+		    // Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r
+		    AppendCharToRedobuff(Ctrl_R);
+		    AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O);
+		    AppendCharToRedobuff(regname == 0 ? '"' : regname);
+		}
+	    }
+	    return FALSE;
+	}
+    }
+
+    // When dragging or button-up stay in the same window.
+    if (!is_click)
+	jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
+
+    start_visual.lnum = 0;
+
+    // Check for clicking in the tab page line.
+    if (mouse_row == 0 && firstwin->w_winrow > 0)
+    {
+	if (is_drag)
+	{
+	    if (in_tab_line)
+	    {
+		c1 = TabPageIdxs[mouse_col];
+		tabpage_move(c1 <= 0 ? 9999 : c1 < tabpage_index(curtab)
+								? c1 - 1 : c1);
+	    }
+	    return FALSE;
+	}
+
+	// click in a tab selects that tab page
+	if (is_click
+# ifdef FEAT_CMDWIN
+		&& cmdwin_type == 0
+# endif
+		&& mouse_col < Columns)
+	{
+	    in_tab_line = TRUE;
+	    c1 = TabPageIdxs[mouse_col];
+	    if (c1 >= 0)
+	    {
+		if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+		{
+		    // double click opens new page
+		    end_visual_mode();
+		    tabpage_new();
+		    tabpage_move(c1 == 0 ? 9999 : c1 - 1);
+		}
+		else
+		{
+		    // Go to specified tab page, or next one if not clicking
+		    // on a label.
+		    goto_tabpage(c1);
+
+		    // It's like clicking on the status line of a window.
+		    if (curwin != old_curwin)
+			end_visual_mode();
+		}
+	    }
+	    else
+	    {
+		tabpage_T	*tp;
+
+		// Close the current or specified tab page.
+		if (c1 == -999)
+		    tp = curtab;
+		else
+		    tp = find_tabpage(-c1);
+		if (tp == curtab)
+		{
+		    if (first_tabpage->tp_next != NULL)
+			tabpage_close(FALSE);
+		}
+		else if (tp != NULL)
+		    tabpage_close_other(tp, FALSE);
+	    }
+	}
+	return TRUE;
+    }
+    else if (is_drag && in_tab_line)
+    {
+	c1 = TabPageIdxs[mouse_col];
+	tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
+	return FALSE;
+    }
+
+    // When 'mousemodel' is "popup" or "popup_setpos", translate mouse events:
+    // right button up   -> pop-up menu
+    // shift-left button -> right button
+    // alt-left button   -> alt-right button
+    if (mouse_model_popup())
+    {
+	if (which_button == MOUSE_RIGHT
+			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
+	{
+#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
+	    || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
+	    || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_PHOTON) \
+	    || defined(FEAT_TERM_POPUP_MENU)
+# ifdef FEAT_GUI
+	    if (gui.in_use)
+	    {
+#  if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
+			  || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
+		if (!is_click)
+		    // Ignore right button release events, only shows the popup
+		    // menu on the button down event.
+		    return FALSE;
+#  endif
+#  if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN)
+		if (is_click || is_drag)
+		    // Ignore right button down and drag mouse events.  Windows
+		    // only shows the popup menu on the button up event.
+		    return FALSE;
+#  endif
+	    }
+# endif
+# if defined(FEAT_GUI) && defined(FEAT_TERM_POPUP_MENU)
+	    else
+# endif
+# if defined(FEAT_TERM_POPUP_MENU)
+	    if (!is_click)
+		// Ignore right button release events, only shows the popup
+		// menu on the button down event.
+		return FALSE;
+#endif
+
+	    jump_flags = 0;
+	    if (STRCMP(p_mousem, "popup_setpos") == 0)
+	    {
+		// First set the cursor position before showing the popup
+		// menu.
+		if (VIsual_active)
+		{
+		    pos_T    m_pos;
+
+		    // set MOUSE_MAY_STOP_VIS if we are outside the
+		    // selection or the current window (might have false
+		    // negative here)
+		    if (mouse_row < curwin->w_winrow
+			 || mouse_row
+				  > (curwin->w_winrow + curwin->w_height))
+			jump_flags = MOUSE_MAY_STOP_VIS;
+		    else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER)
+			jump_flags = MOUSE_MAY_STOP_VIS;
+		    else
+		    {
+			if ((LT_POS(curwin->w_cursor, VIsual)
+				    && (LT_POS(m_pos, curwin->w_cursor)
+					|| LT_POS(VIsual, m_pos)))
+				|| (LT_POS(VIsual, curwin->w_cursor)
+				    && (LT_POS(m_pos, VIsual)
+				      || LT_POS(curwin->w_cursor, m_pos))))
+			{
+			    jump_flags = MOUSE_MAY_STOP_VIS;
+			}
+			else if (VIsual_mode == Ctrl_V)
+			{
+			    getvcols(curwin, &curwin->w_cursor, &VIsual,
+						     &leftcol, &rightcol);
+			    getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
+			    if (m_pos.col < leftcol || m_pos.col > rightcol)
+				jump_flags = MOUSE_MAY_STOP_VIS;
+			}
+		    }
+		}
+		else
+		    jump_flags = MOUSE_MAY_STOP_VIS;
+	    }
+	    if (jump_flags)
+	    {
+		jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
+		update_curbuf(VIsual_active ? INVERTED : VALID);
+		setcursor();
+		out_flush();    // Update before showing popup menu
+	    }
+# ifdef FEAT_MENU
+	    show_popupmenu();
+	    got_click = FALSE;	// ignore release events
+# endif
+	    return (jump_flags & CURSOR_MOVED) != 0;
+#else
+	    return FALSE;
+#endif
+	}
+	if (which_button == MOUSE_LEFT
+				&& (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT)))
+	{
+	    which_button = MOUSE_RIGHT;
+	    mod_mask &= ~MOD_MASK_SHIFT;
+	}
+    }
+
+    if ((State & (NORMAL | INSERT))
+			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
+    {
+	if (which_button == MOUSE_LEFT)
+	{
+	    if (is_click)
+	    {
+		// stop Visual mode for a left click in a window, but not when
+		// on a status line
+		if (VIsual_active)
+		    jump_flags |= MOUSE_MAY_STOP_VIS;
+	    }
+	    else if (mouse_has(MOUSE_VISUAL))
+		jump_flags |= MOUSE_MAY_VIS;
+	}
+	else if (which_button == MOUSE_RIGHT)
+	{
+	    if (is_click && VIsual_active)
+	    {
+		// Remember the start and end of visual before moving the
+		// cursor.
+		if (LT_POS(curwin->w_cursor, VIsual))
+		{
+		    start_visual = curwin->w_cursor;
+		    end_visual = VIsual;
+		}
+		else
+		{
+		    start_visual = VIsual;
+		    end_visual = curwin->w_cursor;
+		}
+	    }
+	    jump_flags |= MOUSE_FOCUS;
+	    if (mouse_has(MOUSE_VISUAL))
+		jump_flags |= MOUSE_MAY_VIS;
+	}
+    }
+
+    // If an operator is pending, ignore all drags and releases until the
+    // next mouse click.
+    if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
+    {
+	got_click = FALSE;
+	oap->motion_type = MCHAR;
+    }
+
+    // When releasing the button let jump_to_mouse() know.
+    if (!is_click && !is_drag)
+	jump_flags |= MOUSE_RELEASED;
+
+    // JUMP!
+    jump_flags = jump_to_mouse(jump_flags,
+			oap == NULL ? NULL : &(oap->inclusive), which_button);
+
+#ifdef FEAT_MENU
+    // A click in the window toolbar has no side effects.
+    if (jump_flags & MOUSE_WINBAR)
+	return FALSE;
+#endif
+    moved = (jump_flags & CURSOR_MOVED);
+    in_status_line = (jump_flags & IN_STATUS_LINE);
+    in_sep_line = (jump_flags & IN_SEP_LINE);
+
+#ifdef FEAT_NETBEANS_INTG
+    if (isNetbeansBuffer(curbuf)
+			    && !(jump_flags & (IN_STATUS_LINE | IN_SEP_LINE)))
+    {
+	int key = KEY2TERMCAP1(c);
+
+	if (key == (int)KE_LEFTRELEASE || key == (int)KE_MIDDLERELEASE
+					       || key == (int)KE_RIGHTRELEASE)
+	    netbeans_button_release(which_button);
+    }
+#endif
+
+    // When jumping to another window, clear a pending operator.  That's a bit
+    // friendlier than beeping and not jumping to that window.
+    if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP)
+	clearop(oap);
+
+#ifdef FEAT_FOLDING
+    if (mod_mask == 0
+	    && !is_drag
+	    && (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN))
+	    && which_button == MOUSE_LEFT)
+    {
+	// open or close a fold at this line
+	if (jump_flags & MOUSE_FOLD_OPEN)
+	    openFold(curwin->w_cursor.lnum, 1L);
+	else
+	    closeFold(curwin->w_cursor.lnum, 1L);
+	// don't move the cursor if still in the same window
+	if (curwin == old_curwin)
+	    curwin->w_cursor = save_cursor;
+    }
+#endif
+
+#if defined(FEAT_CLIPBOARD) && defined(FEAT_CMDWIN)
+    if ((jump_flags & IN_OTHER_WIN) && !VIsual_active && clip_star.available)
+    {
+	clip_modeless(which_button, is_click, is_drag);
+	return FALSE;
+    }
+#endif
+
+    // Set global flag that we are extending the Visual area with mouse
+    // dragging; temporarily minimize 'scrolloff'.
+    if (VIsual_active && is_drag && get_scrolloff_value())
+    {
+	// In the very first line, allow scrolling one line
+	if (mouse_row == 0)
+	    mouse_dragging = 2;
+	else
+	    mouse_dragging = 1;
+    }
+
+    // When dragging the mouse above the window, scroll down.
+    if (is_drag && mouse_row < 0 && !in_status_line)
+    {
+	scroll_redraw(FALSE, 1L);
+	mouse_row = 0;
+    }
+
+    if (start_visual.lnum)		// right click in visual mode
+    {
+       // When ALT is pressed make Visual mode blockwise.
+       if (mod_mask & MOD_MASK_ALT)
+	   VIsual_mode = Ctrl_V;
+
+	// In Visual-block mode, divide the area in four, pick up the corner
+	// that is in the quarter that the cursor is in.
+	if (VIsual_mode == Ctrl_V)
+	{
+	    getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol);
+	    if (curwin->w_curswant > (leftcol + rightcol) / 2)
+		end_visual.col = leftcol;
+	    else
+		end_visual.col = rightcol;
+	    if (curwin->w_cursor.lnum >=
+				    (start_visual.lnum + end_visual.lnum) / 2)
+		end_visual.lnum = start_visual.lnum;
+
+	    // move VIsual to the right column
+	    start_visual = curwin->w_cursor;	    // save the cursor pos
+	    curwin->w_cursor = end_visual;
+	    coladvance(end_visual.col);
+	    VIsual = curwin->w_cursor;
+	    curwin->w_cursor = start_visual;	    // restore the cursor
+	}
+	else
+	{
+	    // If the click is before the start of visual, change the start.
+	    // If the click is after the end of visual, change the end.  If
+	    // the click is inside the visual, change the closest side.
+	    if (LT_POS(curwin->w_cursor, start_visual))
+		VIsual = end_visual;
+	    else if (LT_POS(end_visual, curwin->w_cursor))
+		VIsual = start_visual;
+	    else
+	    {
+		// In the same line, compare column number
+		if (end_visual.lnum == start_visual.lnum)
+		{
+		    if (curwin->w_cursor.col - start_visual.col >
+				    end_visual.col - curwin->w_cursor.col)
+			VIsual = start_visual;
+		    else
+			VIsual = end_visual;
+		}
+
+		// In different lines, compare line number
+		else
+		{
+		    diff = (curwin->w_cursor.lnum - start_visual.lnum) -
+				(end_visual.lnum - curwin->w_cursor.lnum);
+
+		    if (diff > 0)		// closest to end
+			VIsual = start_visual;
+		    else if (diff < 0)	// closest to start
+			VIsual = end_visual;
+		    else			// in the middle line
+		    {
+			if (curwin->w_cursor.col <
+					(start_visual.col + end_visual.col) / 2)
+			    VIsual = end_visual;
+			else
+			    VIsual = start_visual;
+		    }
+		}
+	    }
+	}
+    }
+    // If Visual mode started in insert mode, execute "CTRL-O"
+    else if ((State & INSERT) && VIsual_active)
+	stuffcharReadbuff(Ctrl_O);
+
+    // Middle mouse click: Put text before cursor.
+    if (which_button == MOUSE_MIDDLE)
+    {
+#ifdef FEAT_CLIPBOARD
+	if (clip_star.available && regname == 0)
+	    regname = '*';
+#endif
+	if (yank_register_mline(regname))
+	{
+	    if (mouse_past_bottom)
+		dir = FORWARD;
+	}
+	else if (mouse_past_eol)
+	    dir = FORWARD;
+
+	if (fixindent)
+	{
+	    c1 = (dir == BACKWARD) ? '[' : ']';
+	    c2 = 'p';
+	}
+	else
+	{
+	    c1 = (dir == FORWARD) ? 'p' : 'P';
+	    c2 = NUL;
+	}
+	prep_redo(regname, count, NUL, c1, NUL, c2, NUL);
+
+	// Remember where the paste started, so in edit() Insstart can be set
+	// to this position
+	if (restart_edit != 0)
+	    where_paste_started = curwin->w_cursor;
+	do_put(regname, dir, count, fixindent | PUT_CURSEND);
+    }
+
+#if defined(FEAT_QUICKFIX)
+    // Ctrl-Mouse click or double click in a quickfix window jumps to the
+    // error under the mouse pointer.
+    else if (((mod_mask & MOD_MASK_CTRL)
+		|| (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+	    && bt_quickfix(curbuf))
+    {
+	if (curwin->w_llist_ref == NULL)	// quickfix window
+	    do_cmdline_cmd((char_u *)".cc");
+	else					// location list window
+	    do_cmdline_cmd((char_u *)".ll");
+	got_click = FALSE;		// ignore drag&release now
+    }
+#endif
+
+    // Ctrl-Mouse click (or double click in a help window) jumps to the tag
+    // under the mouse pointer.
+    else if ((mod_mask & MOD_MASK_CTRL) || (curbuf->b_help
+		     && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK))
+    {
+	if (State & INSERT)
+	    stuffcharReadbuff(Ctrl_O);
+	stuffcharReadbuff(Ctrl_RSB);
+	got_click = FALSE;		// ignore drag&release now
+    }
+
+    // Shift-Mouse click searches for the next occurrence of the word under
+    // the mouse pointer
+    else if ((mod_mask & MOD_MASK_SHIFT))
+    {
+	if ((State & INSERT) || (VIsual_active && VIsual_select))
+	    stuffcharReadbuff(Ctrl_O);
+	if (which_button == MOUSE_LEFT)
+	    stuffcharReadbuff('*');
+	else	// MOUSE_RIGHT
+	    stuffcharReadbuff('#');
+    }
+
+    // Handle double clicks, unless on status line
+    else if (in_status_line)
+    {
+#ifdef FEAT_MOUSESHAPE
+	if ((is_drag || is_click) && !drag_status_line)
+	{
+	    drag_status_line = TRUE;
+	    update_mouseshape(-1);
+	}
+#endif
+    }
+    else if (in_sep_line)
+    {
+#ifdef FEAT_MOUSESHAPE
+	if ((is_drag || is_click) && !drag_sep_line)
+	{
+	    drag_sep_line = TRUE;
+	    update_mouseshape(-1);
+	}
+#endif
+    }
+    else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))
+	     && mouse_has(MOUSE_VISUAL))
+    {
+	if (is_click || !VIsual_active)
+	{
+	    if (VIsual_active)
+		orig_cursor = VIsual;
+	    else
+	    {
+		check_visual_highlight();
+		VIsual = curwin->w_cursor;
+		orig_cursor = VIsual;
+		VIsual_active = TRUE;
+		VIsual_reselect = TRUE;
+		// start Select mode if 'selectmode' contains "mouse"
+		may_start_select('o');
+		setmouse();
+	    }
+	    if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+	    {
+		// Double click with ALT pressed makes it blockwise.
+		if (mod_mask & MOD_MASK_ALT)
+		    VIsual_mode = Ctrl_V;
+		else
+		    VIsual_mode = 'v';
+	    }
+	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK)
+		VIsual_mode = 'V';
+	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK)
+		VIsual_mode = Ctrl_V;
+#ifdef FEAT_CLIPBOARD
+	    // Make sure the clipboard gets updated.  Needed because start and
+	    // end may still be the same, and the selection needs to be owned
+	    clip_star.vmode = NUL;
+#endif
+	}
+	// A double click selects a word or a block.
+	if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+	{
+	    pos_T	*pos = NULL;
+	    int		gc;
+
+	    if (is_click)
+	    {
+		// If the character under the cursor (skipping white space) is
+		// not a word character, try finding a match and select a (),
+		// {}, [], #if/#endif, etc. block.
+		end_visual = curwin->w_cursor;
+		while (gc = gchar_pos(&end_visual), VIM_ISWHITE(gc))
+		    inc(&end_visual);
+		if (oap != NULL)
+		    oap->motion_type = MCHAR;
+		if (oap != NULL
+			&& VIsual_mode == 'v'
+			&& !vim_iswordc(gchar_pos(&end_visual))
+			&& EQUAL_POS(curwin->w_cursor, VIsual)
+			&& (pos = findmatch(oap, NUL)) != NULL)
+		{
+		    curwin->w_cursor = *pos;
+		    if (oap->motion_type == MLINE)
+			VIsual_mode = 'V';
+		    else if (*p_sel == 'e')
+		    {
+			if (LT_POS(curwin->w_cursor, VIsual))
+			    ++VIsual.col;
+			else
+			    ++curwin->w_cursor.col;
+		    }
+		}
+	    }
+
+	    if (pos == NULL && (is_click || is_drag))
+	    {
+		// When not found a match or when dragging: extend to include
+		// a word.
+		if (LT_POS(curwin->w_cursor, orig_cursor))
+		{
+		    find_start_of_word(&curwin->w_cursor);
+		    find_end_of_word(&VIsual);
+		}
+		else
+		{
+		    find_start_of_word(&VIsual);
+		    if (*p_sel == 'e' && *ml_get_cursor() != NUL)
+			curwin->w_cursor.col +=
+					 (*mb_ptr2len)(ml_get_cursor());
+		    find_end_of_word(&curwin->w_cursor);
+		}
+	    }
+	    curwin->w_set_curswant = TRUE;
+	}
+	if (is_click)
+	    redraw_curbuf_later(INVERTED);	// update the inversion
+    }
+    else if (VIsual_active && !old_active)
+    {
+	if (mod_mask & MOD_MASK_ALT)
+	    VIsual_mode = Ctrl_V;
+	else
+	    VIsual_mode = 'v';
+    }
+
+    // If Visual mode changed show it later.
+    if ((!VIsual_active && old_active && mode_displayed)
+	    || (VIsual_active && p_smd && msg_silent == 0
+				 && (!old_active || VIsual_mode != old_mode)))
+	redraw_cmdline = TRUE;
+
+    return moved;
+}
+
+    void
+ins_mouse(int c)
+{
+    pos_T	tpos;
+    win_T	*old_curwin = curwin;
+
+# ifdef FEAT_GUI
+    // When GUI is active, also move/paste when 'mouse' is empty
+    if (!gui.in_use)
+# endif
+	if (!mouse_has(MOUSE_INSERT))
+	    return;
+
+    undisplay_dollar();
+    tpos = curwin->w_cursor;
+    if (do_mouse(NULL, c, BACKWARD, 1L, 0))
+    {
+	win_T	*new_curwin = curwin;
+
+	if (curwin != old_curwin && win_valid(old_curwin))
+	{
+	    // Mouse took us to another window.  We need to go back to the
+	    // previous one to stop insert there properly.
+	    curwin = old_curwin;
+	    curbuf = curwin->w_buffer;
+#ifdef FEAT_JOB_CHANNEL
+	    if (bt_prompt(curbuf))
+		// Restart Insert mode when re-entering the prompt buffer.
+		curbuf->b_prompt_insert = 'A';
+#endif
+	}
+	start_arrow(curwin == old_curwin ? &tpos : NULL);
+	if (curwin != new_curwin && win_valid(new_curwin))
+	{
+	    curwin = new_curwin;
+	    curbuf = curwin->w_buffer;
+	}
+# ifdef FEAT_CINDENT
+	set_can_cindent(TRUE);
+# endif
+    }
+
+    // redraw status lines (in case another window became active)
+    redraw_statuslines();
+}
+
+    void
+ins_mousescroll(int dir)
+{
+    pos_T	tpos;
+    win_T	*old_curwin = curwin, *wp;
+    int		did_scroll = FALSE;
+
+    tpos = curwin->w_cursor;
+
+    if (mouse_row >= 0 && mouse_col >= 0)
+    {
+	int row, col;
+
+	row = mouse_row;
+	col = mouse_col;
+
+	// find the window at the pointer coordinates
+	wp = mouse_find_win(&row, &col, FIND_POPUP);
+	if (wp == NULL)
+	    return;
+	curwin = wp;
+	curbuf = curwin->w_buffer;
+    }
+    if (curwin == old_curwin)
+	undisplay_dollar();
+
+    // Don't scroll the window in which completion is being done.
+    if (!pum_visible() || curwin != old_curwin)
+    {
+	if (dir == MSCR_DOWN || dir == MSCR_UP)
+	{
+	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+		scroll_redraw(dir,
+			(long)(curwin->w_botline - curwin->w_topline));
+	    else
+		scroll_redraw(dir, 3L);
+# ifdef FEAT_TEXT_PROP
+	if (WIN_IS_POPUP(curwin))
+	    popup_set_firstline(curwin);
+# endif
+	}
+#ifdef FEAT_GUI
+	else
+	{
+	    int val, step = 6;
+
+	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+		step = curwin->w_width;
+	    val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step);
+	    if (val < 0)
+		val = 0;
+	    gui_do_horiz_scroll(val, TRUE);
+	}
+#endif
+	did_scroll = TRUE;
+    }
+
+    curwin->w_redr_status = TRUE;
+
+    curwin = old_curwin;
+    curbuf = curwin->w_buffer;
+
+    // The popup menu may overlay the window, need to redraw it.
+    // TODO: Would be more efficient to only redraw the windows that are
+    // overlapped by the popup menu.
+    if (pum_visible() && did_scroll)
+    {
+	redraw_all_later(NOT_VALID);
+	ins_compl_show_pum();
+    }
+
+    if (!EQUAL_POS(curwin->w_cursor, tpos))
+    {
+	start_arrow(&tpos);
+# ifdef FEAT_CINDENT
+	set_can_cindent(TRUE);
+# endif
+    }
+}
+
+/*
+ * Return TRUE if "c" is a mouse key.
+ */
+    int
+is_mouse_key(int c)
+{
+    return c == K_LEFTMOUSE
+	|| c == K_LEFTMOUSE_NM
+	|| c == K_LEFTDRAG
+	|| c == K_LEFTRELEASE
+	|| c == K_LEFTRELEASE_NM
+	|| c == K_MOUSEMOVE
+	|| c == K_MIDDLEMOUSE
+	|| c == K_MIDDLEDRAG
+	|| c == K_MIDDLERELEASE
+	|| c == K_RIGHTMOUSE
+	|| c == K_RIGHTDRAG
+	|| c == K_RIGHTRELEASE
+	|| c == K_MOUSEDOWN
+	|| c == K_MOUSEUP
+	|| c == K_MOUSELEFT
+	|| c == K_MOUSERIGHT
+	|| c == K_X1MOUSE
+	|| c == K_X1DRAG
+	|| c == K_X1RELEASE
+	|| c == K_X2MOUSE
+	|| c == K_X2DRAG
+	|| c == K_X2RELEASE;
+}
+
+static struct mousetable
+{
+    int	    pseudo_code;	// Code for pseudo mouse event
+    int	    button;		// Which mouse button is it?
+    int	    is_click;		// Is it a mouse button click event?
+    int	    is_drag;		// Is it a mouse drag event?
+} mouse_table[] =
+{
+    {(int)KE_LEFTMOUSE,		MOUSE_LEFT,	TRUE,	FALSE},
+#ifdef FEAT_GUI
+    {(int)KE_LEFTMOUSE_NM,	MOUSE_LEFT,	TRUE,	FALSE},
+#endif
+    {(int)KE_LEFTDRAG,		MOUSE_LEFT,	FALSE,	TRUE},
+    {(int)KE_LEFTRELEASE,	MOUSE_LEFT,	FALSE,	FALSE},
+#ifdef FEAT_GUI
+    {(int)KE_LEFTRELEASE_NM,	MOUSE_LEFT,	FALSE,	FALSE},
+#endif
+    {(int)KE_MIDDLEMOUSE,	MOUSE_MIDDLE,	TRUE,	FALSE},
+    {(int)KE_MIDDLEDRAG,	MOUSE_MIDDLE,	FALSE,	TRUE},
+    {(int)KE_MIDDLERELEASE,	MOUSE_MIDDLE,	FALSE,	FALSE},
+    {(int)KE_RIGHTMOUSE,	MOUSE_RIGHT,	TRUE,	FALSE},
+    {(int)KE_RIGHTDRAG,		MOUSE_RIGHT,	FALSE,	TRUE},
+    {(int)KE_RIGHTRELEASE,	MOUSE_RIGHT,	FALSE,	FALSE},
+    {(int)KE_X1MOUSE,		MOUSE_X1,	TRUE,	FALSE},
+    {(int)KE_X1DRAG,		MOUSE_X1,	FALSE,	TRUE},
+    {(int)KE_X1RELEASE,		MOUSE_X1,	FALSE,	FALSE},
+    {(int)KE_X2MOUSE,		MOUSE_X2,	TRUE,	FALSE},
+    {(int)KE_X2DRAG,		MOUSE_X2,	FALSE,	TRUE},
+    {(int)KE_X2RELEASE,		MOUSE_X2,	FALSE,	FALSE},
+    // DRAG without CLICK
+    {(int)KE_MOUSEMOVE,		MOUSE_RELEASE,	FALSE,	TRUE},
+    // RELEASE without CLICK
+    {(int)KE_IGNORE,		MOUSE_RELEASE,	FALSE,	FALSE},
+    {0,				0,		0,	0},
+};
+
+/*
+ * Look up the given mouse code to return the relevant information in the other
+ * arguments.  Return which button is down or was released.
+ */
+    int
+get_mouse_button(int code, int *is_click, int *is_drag)
+{
+    int	    i;
+
+    for (i = 0; mouse_table[i].pseudo_code; i++)
+	if (code == mouse_table[i].pseudo_code)
+	{
+	    *is_click = mouse_table[i].is_click;
+	    *is_drag = mouse_table[i].is_drag;
+	    return mouse_table[i].button;
+	}
+    return 0;	    // Shouldn't get here
+}
+
+/*
+ * Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
+ * the given information about which mouse button is down, and whether the
+ * mouse was clicked, dragged or released.
+ */
+    int
+get_pseudo_mouse_code(
+    int	    button,	// eg MOUSE_LEFT
+    int	    is_click,
+    int	    is_drag)
+{
+    int	    i;
+
+    for (i = 0; mouse_table[i].pseudo_code; i++)
+	if (button == mouse_table[i].button
+	    && is_click == mouse_table[i].is_click
+	    && is_drag == mouse_table[i].is_drag)
+	{
+#ifdef FEAT_GUI
+	    // Trick: a non mappable left click and release has mouse_col -1
+	    // or added MOUSE_COLOFF.  Used for 'mousefocus' in
+	    // gui_mouse_moved()
+	    if (mouse_col < 0 || mouse_col > MOUSE_COLOFF)
+	    {
+		if (mouse_col < 0)
+		    mouse_col = 0;
+		else
+		    mouse_col -= MOUSE_COLOFF;
+		if (mouse_table[i].pseudo_code == (int)KE_LEFTMOUSE)
+		    return (int)KE_LEFTMOUSE_NM;
+		if (mouse_table[i].pseudo_code == (int)KE_LEFTRELEASE)
+		    return (int)KE_LEFTRELEASE_NM;
+	    }
+#endif
+	    return mouse_table[i].pseudo_code;
+	}
+    return (int)KE_IGNORE;	    // not recognized, ignore it
+}
+
+# ifdef FEAT_MOUSE_TTY
+#  define HMT_NORMAL	1
+#  define HMT_NETTERM	2
+#  define HMT_DEC	4
+#  define HMT_JSBTERM	8
+#  define HMT_PTERM	16
+#  define HMT_URXVT	32
+#  define HMT_GPM	64
+#  define HMT_SGR	128
+#  define HMT_SGR_REL	256
+static int has_mouse_termcode = 0;
+# endif
+
+# if (!defined(UNIX) || defined(FEAT_MOUSE_TTY)) || defined(PROTO)
+    void
+set_mouse_termcode(
+    int		n,	// KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE
+    char_u	*s)
+{
+    char_u	name[2];
+
+    name[0] = n;
+    name[1] = KE_FILLER;
+    add_termcode(name, s, FALSE);
+#  ifdef FEAT_MOUSE_TTY
+#   ifdef FEAT_MOUSE_JSB
+    if (n == KS_JSBTERM_MOUSE)
+	has_mouse_termcode |= HMT_JSBTERM;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_NET
+    if (n == KS_NETTERM_MOUSE)
+	has_mouse_termcode |= HMT_NETTERM;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_DEC
+    if (n == KS_DEC_MOUSE)
+	has_mouse_termcode |= HMT_DEC;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_PTERM
+    if (n == KS_PTERM_MOUSE)
+	has_mouse_termcode |= HMT_PTERM;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_URXVT
+    if (n == KS_URXVT_MOUSE)
+	has_mouse_termcode |= HMT_URXVT;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_GPM
+    if (n == KS_GPM_MOUSE)
+	has_mouse_termcode |= HMT_GPM;
+    else
+#   endif
+    if (n == KS_SGR_MOUSE)
+	has_mouse_termcode |= HMT_SGR;
+    else if (n == KS_SGR_MOUSE_RELEASE)
+	has_mouse_termcode |= HMT_SGR_REL;
+    else
+	has_mouse_termcode |= HMT_NORMAL;
+#  endif
+}
+# endif
+
+# if ((defined(UNIX) || defined(VMS)) \
+	&& defined(FEAT_MOUSE_TTY)) || defined(PROTO)
+    void
+del_mouse_termcode(
+    int		n)	// KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE
+{
+    char_u	name[2];
+
+    name[0] = n;
+    name[1] = KE_FILLER;
+    del_termcode(name);
+#  ifdef FEAT_MOUSE_TTY
+#   ifdef FEAT_MOUSE_JSB
+    if (n == KS_JSBTERM_MOUSE)
+	has_mouse_termcode &= ~HMT_JSBTERM;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_NET
+    if (n == KS_NETTERM_MOUSE)
+	has_mouse_termcode &= ~HMT_NETTERM;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_DEC
+    if (n == KS_DEC_MOUSE)
+	has_mouse_termcode &= ~HMT_DEC;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_PTERM
+    if (n == KS_PTERM_MOUSE)
+	has_mouse_termcode &= ~HMT_PTERM;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_URXVT
+    if (n == KS_URXVT_MOUSE)
+	has_mouse_termcode &= ~HMT_URXVT;
+    else
+#   endif
+#   ifdef FEAT_MOUSE_GPM
+    if (n == KS_GPM_MOUSE)
+	has_mouse_termcode &= ~HMT_GPM;
+    else
+#   endif
+    if (n == KS_SGR_MOUSE)
+	has_mouse_termcode &= ~HMT_SGR;
+    else if (n == KS_SGR_MOUSE_RELEASE)
+	has_mouse_termcode &= ~HMT_SGR_REL;
+    else
+	has_mouse_termcode &= ~HMT_NORMAL;
+#  endif
+}
+# endif
+
+/*
+ * setmouse() - switch mouse on/off depending on current mode and 'mouse'
+ */
+    void
+setmouse(void)
+{
+# ifdef FEAT_MOUSE_TTY
+    int	    checkfor;
+# endif
+
+# ifdef FEAT_MOUSESHAPE
+    update_mouseshape(-1);
+# endif
+
+# ifdef FEAT_MOUSE_TTY // Should be outside proc, but may break MOUSESHAPE
+#  ifdef FEAT_GUI
+    // In the GUI the mouse is always enabled.
+    if (gui.in_use)
+	return;
+#  endif
+    // be quick when mouse is off
+    if (*p_mouse == NUL || has_mouse_termcode == 0)
+	return;
+
+    // don't switch mouse on when not in raw mode (Ex mode)
+    if (cur_tmode != TMODE_RAW)
+    {
+	mch_setmouse(FALSE);
+	return;
+    }
+
+    if (VIsual_active)
+	checkfor = MOUSE_VISUAL;
+    else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE)
+	checkfor = MOUSE_RETURN;
+    else if (State & INSERT)
+	checkfor = MOUSE_INSERT;
+    else if (State & CMDLINE)
+	checkfor = MOUSE_COMMAND;
+    else if (State == CONFIRM || State == EXTERNCMD)
+	checkfor = ' '; // don't use mouse for ":confirm" or ":!cmd"
+    else
+	checkfor = MOUSE_NORMAL;    // assume normal mode
+
+    if (mouse_has(checkfor))
+	mch_setmouse(TRUE);
+    else
+	mch_setmouse(FALSE);
+# endif
+}
+
+/*
+ * Return TRUE if
+ * - "c" is in 'mouse', or
+ * - 'a' is in 'mouse' and "c" is in MOUSE_A, or
+ * - the current buffer is a help file and 'h' is in 'mouse' and we are in a
+ *   normal editing mode (not at hit-return message).
+ */
+    int
+mouse_has(int c)
+{
+    char_u	*p;
+
+    for (p = p_mouse; *p; ++p)
+	switch (*p)
+	{
+	    case 'a': if (vim_strchr((char_u *)MOUSE_A, c) != NULL)
+			  return TRUE;
+		      break;
+	    case MOUSE_HELP: if (c != MOUSE_RETURN && curbuf->b_help)
+				 return TRUE;
+			     break;
+	    default: if (c == *p) return TRUE; break;
+	}
+    return FALSE;
+}
+
+/*
+ * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos".
+ */
+    int
+mouse_model_popup(void)
+{
+    return (p_mousem[0] == 'p');
+}
+
+/*
+ * Move the cursor to the specified row and column on the screen.
+ * Change current window if necessary.	Returns an integer with the
+ * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
+ *
+ * The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
+ * The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
+ *
+ * If flags has MOUSE_FOCUS, then the current window will not be changed, and
+ * if the mouse is outside the window then the text will scroll, or if the
+ * mouse was previously on a status line, then the status line may be dragged.
+ *
+ * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
+ * cursor is moved unless the cursor was on a status line.
+ * This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
+ * IN_SEP_LINE depending on where the cursor was clicked.
+ *
+ * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
+ * the mouse is on the status line of the same window.
+ *
+ * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
+ * the last call.
+ *
+ * If flags has MOUSE_SETPOS, nothing is done, only the current position is
+ * remembered.
+ */
+    int
+jump_to_mouse(
+    int		flags,
+    int		*inclusive,	// used for inclusive operator, can be NULL
+    int		which_button)	// MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE
+{
+    static int	on_status_line = 0;	// #lines below bottom of window
+    static int	on_sep_line = 0;	// on separator right of window
+#ifdef FEAT_MENU
+    static int  in_winbar = FALSE;
+#endif
+#ifdef FEAT_TEXT_PROP
+    static int   in_popup_win = FALSE;
+    static win_T *click_in_popup_win = NULL;
+#endif
+    static int	prev_row = -1;
+    static int	prev_col = -1;
+    static win_T *dragwin = NULL;	// window being dragged
+    static int	did_drag = FALSE;	// drag was noticed
+
+    win_T	*wp, *old_curwin;
+    pos_T	old_cursor;
+    int		count;
+    int		first;
+    int		row = mouse_row;
+    int		col = mouse_col;
+#ifdef FEAT_FOLDING
+    int		mouse_char;
+#endif
+
+    mouse_past_bottom = FALSE;
+    mouse_past_eol = FALSE;
+
+    if (flags & MOUSE_RELEASED)
+    {
+	// On button release we may change window focus if positioned on a
+	// status line and no dragging happened.
+	if (dragwin != NULL && !did_drag)
+	    flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
+	dragwin = NULL;
+	did_drag = FALSE;
+#ifdef FEAT_TEXT_PROP
+	if (click_in_popup_win != NULL && popup_dragwin == NULL)
+	    popup_close_for_mouse_click(click_in_popup_win);
+
+	popup_dragwin = NULL;
+	click_in_popup_win = NULL;
+#endif
+    }
+
+    if ((flags & MOUSE_DID_MOVE)
+	    && prev_row == mouse_row
+	    && prev_col == mouse_col)
+    {
+retnomove:
+	// before moving the cursor for a left click which is NOT in a status
+	// line, stop Visual mode
+	if (on_status_line)
+	    return IN_STATUS_LINE;
+	if (on_sep_line)
+	    return IN_SEP_LINE;
+#ifdef FEAT_MENU
+	if (in_winbar)
+	{
+	    // A quick second click may arrive as a double-click, but we use it
+	    // as a second click in the WinBar.
+	    if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED))
+	    {
+		wp = mouse_find_win(&row, &col, FAIL_POPUP);
+		if (wp == NULL)
+		    return IN_UNKNOWN;
+		winbar_click(wp, col);
+	    }
+	    return IN_OTHER_WIN | MOUSE_WINBAR;
+	}
+#endif
+	if (flags & MOUSE_MAY_STOP_VIS)
+	{
+	    end_visual_mode();
+	    redraw_curbuf_later(INVERTED);	// delete the inversion
+	}
+#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
+	// Continue a modeless selection in another window.
+	if (cmdwin_type != 0 && row < curwin->w_winrow)
+	    return IN_OTHER_WIN;
+#endif
+#ifdef FEAT_TEXT_PROP
+	// Continue a modeless selection in a popup window or dragging it.
+	if (in_popup_win)
+	{
+	    click_in_popup_win = NULL;  // don't close it on release
+	    if (popup_dragwin != NULL)
+	    {
+		// dragging a popup window
+		popup_drag(popup_dragwin);
+		return IN_UNKNOWN;
+	    }
+	    return IN_OTHER_WIN;
+	}
+#endif
+	return IN_BUFFER;
+    }
+
+    prev_row = mouse_row;
+    prev_col = mouse_col;
+
+    if (flags & MOUSE_SETPOS)
+	goto retnomove;				// ugly goto...
+
+#ifdef FEAT_FOLDING
+    // Remember the character under the mouse, it might be a '-' or '+' in the
+    // fold column.
+    if (row >= 0 && row < Rows && col >= 0 && col <= Columns
+						       && ScreenLines != NULL)
+	mouse_char = ScreenLines[LineOffset[row] + col];
+    else
+	mouse_char = ' ';
+#endif
+
+    old_curwin = curwin;
+    old_cursor = curwin->w_cursor;
+
+    if (!(flags & MOUSE_FOCUS))
+    {
+	if (row < 0 || col < 0)			// check if it makes sense
+	    return IN_UNKNOWN;
+
+	// find the window where the row is in and adjust "row" and "col" to be
+	// relative to top-left of the window
+	wp = mouse_find_win(&row, &col, FIND_POPUP);
+	if (wp == NULL)
+	    return IN_UNKNOWN;
+	dragwin = NULL;
+
+#ifdef FEAT_TEXT_PROP
+	// Click in a popup window may start dragging or modeless selection,
+	// but not much else.
+	if (WIN_IS_POPUP(wp))
+	{
+	    on_sep_line = 0;
+	    in_popup_win = TRUE;
+	    if (which_button == MOUSE_LEFT && popup_close_if_on_X(wp, row, col))
+	    {
+		return IN_UNKNOWN;
+	    }
+	    else if ((wp->w_popup_flags & (POPF_DRAG | POPF_RESIZE))
+					      && popup_on_border(wp, row, col))
+	    {
+		popup_dragwin = wp;
+		popup_start_drag(wp, row, col);
+		return IN_UNKNOWN;
+	    }
+	    // Only close on release, otherwise it's not possible to drag or do
+	    // modeless selection.
+	    else if (wp->w_popup_close == POPCLOSE_CLICK
+		    && which_button == MOUSE_LEFT)
+	    {
+		click_in_popup_win = wp;
+	    }
+	    else if (which_button == MOUSE_LEFT)
+		// If the click is in the scrollbar, may scroll up/down.
+		popup_handle_scrollbar_click(wp, row, col);
+# ifdef FEAT_CLIPBOARD
+	    return IN_OTHER_WIN;
+# else
+	    return IN_UNKNOWN;
+# endif
+	}
+	in_popup_win = FALSE;
+	popup_dragwin = NULL;
+#endif
+#ifdef FEAT_MENU
+	if (row == -1)
+	{
+	    // A click in the window toolbar does not enter another window or
+	    // change Visual highlighting.
+	    winbar_click(wp, col);
+	    in_winbar = TRUE;
+	    return IN_OTHER_WIN | MOUSE_WINBAR;
+	}
+	in_winbar = FALSE;
+#endif
+
+	// winpos and height may change in win_enter()!
+	if (row >= wp->w_height)		// In (or below) status line
+	{
+	    on_status_line = row - wp->w_height + 1;
+	    dragwin = wp;
+	}
+	else
+	    on_status_line = 0;
+	if (col >= wp->w_width)		// In separator line
+	{
+	    on_sep_line = col - wp->w_width + 1;
+	    dragwin = wp;
+	}
+	else
+	    on_sep_line = 0;
+
+	// The rightmost character of the status line might be a vertical
+	// separator character if there is no connecting window to the right.
+	if (on_status_line && on_sep_line)
+	{
+	    if (stl_connected(wp))
+		on_sep_line = 0;
+	    else
+		on_status_line = 0;
+	}
+
+	// Before jumping to another buffer, or moving the cursor for a left
+	// click, stop Visual mode.
+	if (VIsual_active
+		&& (wp->w_buffer != curwin->w_buffer
+		    || (!on_status_line && !on_sep_line
+#ifdef FEAT_FOLDING
+			&& (
+# ifdef FEAT_RIGHTLEFT
+			    wp->w_p_rl ? col < wp->w_width - wp->w_p_fdc :
+# endif
+			    col >= wp->w_p_fdc
+# ifdef FEAT_CMDWIN
+				  + (cmdwin_type == 0 && wp == curwin ? 0 : 1)
+# endif
+			    )
+#endif
+			&& (flags & MOUSE_MAY_STOP_VIS))))
+	{
+	    end_visual_mode();
+	    redraw_curbuf_later(INVERTED);	// delete the inversion
+	}
+#ifdef FEAT_CMDWIN
+	if (cmdwin_type != 0 && wp != curwin)
+	{
+	    // A click outside the command-line window: Use modeless
+	    // selection if possible.  Allow dragging the status lines.
+	    on_sep_line = 0;
+# ifdef FEAT_CLIPBOARD
+	    if (on_status_line)
+		return IN_STATUS_LINE;
+	    return IN_OTHER_WIN;
+# else
+	    row = 0;
+	    col += wp->w_wincol;
+	    wp = curwin;
+# endif
+	}
+#endif
+	// Only change window focus when not clicking on or dragging the
+	// status line.  Do change focus when releasing the mouse button
+	// (MOUSE_FOCUS was set above if we dragged first).
+	if (dragwin == NULL || (flags & MOUSE_RELEASED))
+	    win_enter(wp, TRUE);		// can make wp invalid!
+
+	if (curwin != old_curwin)
+	{
+#ifdef CHECK_DOUBLE_CLICK
+	    // set topline, to be able to check for double click ourselves
+	    set_mouse_topline(curwin);
+#endif
+#ifdef FEAT_TERMINAL
+	    // when entering a terminal window may change state
+	    term_win_entered();
+#endif
+	}
+	if (on_status_line)			// In (or below) status line
+	{
+	    // Don't use start_arrow() if we're in the same window
+	    if (curwin == old_curwin)
+		return IN_STATUS_LINE;
+	    else
+		return IN_STATUS_LINE | CURSOR_MOVED;
+	}
+	if (on_sep_line)			// In (or below) status line
+	{
+	    // Don't use start_arrow() if we're in the same window
+	    if (curwin == old_curwin)
+		return IN_SEP_LINE;
+	    else
+		return IN_SEP_LINE | CURSOR_MOVED;
+	}
+
+	curwin->w_cursor.lnum = curwin->w_topline;
+#ifdef FEAT_GUI
+	// remember topline, needed for double click
+	gui_prev_topline = curwin->w_topline;
+# ifdef FEAT_DIFF
+	gui_prev_topfill = curwin->w_topfill;
+# endif
+#endif
+    }
+    else if (on_status_line && which_button == MOUSE_LEFT)
+    {
+	if (dragwin != NULL)
+	{
+	    // Drag the status line
+	    count = row - dragwin->w_winrow - dragwin->w_height + 1
+							     - on_status_line;
+	    win_drag_status_line(dragwin, count);
+	    did_drag |= count;
+	}
+	return IN_STATUS_LINE;			// Cursor didn't move
+    }
+    else if (on_sep_line && which_button == MOUSE_LEFT)
+    {
+	if (dragwin != NULL)
+	{
+	    // Drag the separator column
+	    count = col - dragwin->w_wincol - dragwin->w_width + 1
+								- on_sep_line;
+	    win_drag_vsep_line(dragwin, count);
+	    did_drag |= count;
+	}
+	return IN_SEP_LINE;			// Cursor didn't move
+    }
+#ifdef FEAT_MENU
+    else if (in_winbar)
+    {
+	// After a click on the window toolbar don't start Visual mode.
+	return IN_OTHER_WIN | MOUSE_WINBAR;
+    }
+#endif
+    else // keep_window_focus must be TRUE
+    {
+	// before moving the cursor for a left click, stop Visual mode
+	if (flags & MOUSE_MAY_STOP_VIS)
+	{
+	    end_visual_mode();
+	    redraw_curbuf_later(INVERTED);	// delete the inversion
+	}
+
+#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
+	// Continue a modeless selection in another window.
+	if (cmdwin_type != 0 && row < curwin->w_winrow)
+	    return IN_OTHER_WIN;
+#endif
+#ifdef FEAT_TEXT_PROP
+	if (in_popup_win)
+	{
+	    if (popup_dragwin != NULL)
+	    {
+		// dragging a popup window
+		popup_drag(popup_dragwin);
+		return IN_UNKNOWN;
+	    }
+	    // continue a modeless selection in a popup window
+	    click_in_popup_win = NULL;
+	    return IN_OTHER_WIN;
+	}
+#endif
+
+	row -= W_WINROW(curwin);
+	col -= curwin->w_wincol;
+
+	// When clicking beyond the end of the window, scroll the screen.
+	// Scroll by however many rows outside the window we are.
+	if (row < 0)
+	{
+	    count = 0;
+	    for (first = TRUE; curwin->w_topline > 1; )
+	    {
+#ifdef FEAT_DIFF
+		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
+		    ++count;
+		else
+#endif
+		    count += plines(curwin->w_topline - 1);
+		if (!first && count > -row)
+		    break;
+		first = FALSE;
+#ifdef FEAT_FOLDING
+		(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+#ifdef FEAT_DIFF
+		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
+		    ++curwin->w_topfill;
+		else
+#endif
+		{
+		    --curwin->w_topline;
+#ifdef FEAT_DIFF
+		    curwin->w_topfill = 0;
+#endif
+		}
+	    }
+#ifdef FEAT_DIFF
+	    check_topfill(curwin, FALSE);
+#endif
+	    curwin->w_valid &=
+		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+	    redraw_later(VALID);
+	    row = 0;
+	}
+	else if (row >= curwin->w_height)
+	{
+	    count = 0;
+	    for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; )
+	    {
+#ifdef FEAT_DIFF
+		if (curwin->w_topfill > 0)
+		    ++count;
+		else
+#endif
+		    count += plines(curwin->w_topline);
+		if (!first && count > row - curwin->w_height + 1)
+		    break;
+		first = FALSE;
+#ifdef FEAT_FOLDING
+		if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
+			&& curwin->w_topline == curbuf->b_ml.ml_line_count)
+		    break;
+#endif
+#ifdef FEAT_DIFF
+		if (curwin->w_topfill > 0)
+		    --curwin->w_topfill;
+		else
+#endif
+		{
+		    ++curwin->w_topline;
+#ifdef FEAT_DIFF
+		    curwin->w_topfill =
+				   diff_check_fill(curwin, curwin->w_topline);
+#endif
+		}
+	    }
+#ifdef FEAT_DIFF
+	    check_topfill(curwin, FALSE);
+#endif
+	    redraw_later(VALID);
+	    curwin->w_valid &=
+		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+	    row = curwin->w_height - 1;
+	}
+	else if (row == 0)
+	{
+	    // When dragging the mouse, while the text has been scrolled up as
+	    // far as it goes, moving the mouse in the top line should scroll
+	    // the text down (done later when recomputing w_topline).
+	    if (mouse_dragging > 0
+		    && curwin->w_cursor.lnum
+				       == curwin->w_buffer->b_ml.ml_line_count
+		    && curwin->w_cursor.lnum == curwin->w_topline)
+		curwin->w_valid &= ~(VALID_TOPLINE);
+	}
+    }
+
+#ifdef FEAT_FOLDING
+    // Check for position outside of the fold column.
+    if (
+# ifdef FEAT_RIGHTLEFT
+	    curwin->w_p_rl ? col < curwin->w_width - curwin->w_p_fdc :
+# endif
+	    col >= curwin->w_p_fdc
+#  ifdef FEAT_CMDWIN
+				+ (cmdwin_type == 0 ? 0 : 1)
+#  endif
+       )
+	mouse_char = ' ';
+#endif
+
+    // compute the position in the buffer line from the posn on the screen
+    if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum, NULL))
+	mouse_past_bottom = TRUE;
+
+    // Start Visual mode before coladvance(), for when 'sel' != "old"
+    if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
+    {
+	check_visual_highlight();
+	VIsual = old_cursor;
+	VIsual_active = TRUE;
+	VIsual_reselect = TRUE;
+	// if 'selectmode' contains "mouse", start Select mode
+	may_start_select('o');
+	setmouse();
+	if (p_smd && msg_silent == 0)
+	    redraw_cmdline = TRUE;	// show visual mode later
+    }
+
+    curwin->w_curswant = col;
+    curwin->w_set_curswant = FALSE;	// May still have been TRUE
+    if (coladvance(col) == FAIL)	// Mouse click beyond end of line
+    {
+	if (inclusive != NULL)
+	    *inclusive = TRUE;
+	mouse_past_eol = TRUE;
+    }
+    else if (inclusive != NULL)
+	*inclusive = FALSE;
+
+    count = IN_BUFFER;
+    if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
+	    || curwin->w_cursor.col != old_cursor.col)
+	count |= CURSOR_MOVED;		// Cursor has moved
+
+# ifdef FEAT_FOLDING
+    if (mouse_char == '+')
+	count |= MOUSE_FOLD_OPEN;
+    else if (mouse_char != ' ')
+	count |= MOUSE_FOLD_CLOSE;
+# endif
+
+    return count;
+}
+
+/*
+ * Mouse scroll wheel: Default action is to scroll three lines, or one page
+ * when Shift or Ctrl is used.
+ * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or
+ * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2)
+ */
+    void
+nv_mousescroll(cmdarg_T *cap)
+{
+    win_T *old_curwin = curwin, *wp;
+
+    if (mouse_row >= 0 && mouse_col >= 0)
+    {
+	int row, col;
+
+	row = mouse_row;
+	col = mouse_col;
+
+	// find the window at the pointer coordinates
+	wp = mouse_find_win(&row, &col, FIND_POPUP);
+	if (wp == NULL)
+	    return;
+#ifdef FEAT_TEXT_PROP
+	if (WIN_IS_POPUP(wp) && !wp->w_has_scrollbar)
+	    return;
+#endif
+	curwin = wp;
+	curbuf = curwin->w_buffer;
+    }
+
+    if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
+    {
+# ifdef FEAT_TERMINAL
+	if (term_use_loop())
+	    // This window is a terminal window, send the mouse event there.
+	    // Set "typed" to FALSE to avoid an endless loop.
+	    send_keys_to_term(curbuf->b_term, cap->cmdchar, FALSE);
+	else
+# endif
+	if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+	{
+	    (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
+	}
+	else
+	{
+	    // Don't scroll more than half the window height.
+	    if (curwin->w_height < 6)
+	    {
+		cap->count1 = curwin->w_height / 2;
+		if (cap->count1 == 0)
+		    cap->count1 = 1;
+	    }
+	    else
+		cap->count1 = 3;
+	    cap->count0 = cap->count1;
+	    nv_scroll_line(cap);
+	}
+#ifdef FEAT_TEXT_PROP
+	if (WIN_IS_POPUP(curwin))
+	    popup_set_firstline(curwin);
+#endif
+    }
+# ifdef FEAT_GUI
+    else
+    {
+	// Horizontal scroll - only allowed when 'wrap' is disabled
+	if (!curwin->w_p_wrap)
+	{
+	    int val, step = 6;
+
+	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+		step = curwin->w_width;
+	    val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step);
+	    if (val < 0)
+		val = 0;
+
+	    gui_do_horiz_scroll(val, TRUE);
+	}
+    }
+# endif
+# ifdef FEAT_SYN_HL
+    if (curwin != old_curwin && curwin->w_p_cul)
+	redraw_for_cursorline(curwin);
+# endif
+
+    curwin->w_redr_status = TRUE;
+
+    curwin = old_curwin;
+    curbuf = curwin->w_buffer;
+}
+
+/*
+ * Mouse clicks and drags.
+ */
+    void
+nv_mouse(cmdarg_T *cap)
+{
+    (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0);
+}
+#endif // FEAT_MOUSE
+
+// Functions also used for popup windows.
+#if defined(FEAT_MOUSE) || defined(FEAT_TEXT_PROP) || defined(PROTO)
+
+/*
+ * Compute the buffer line position from the screen position "rowp" / "colp" in
+ * window "win".
+ * "plines_cache" can be NULL (no cache) or an array with "win->w_height"
+ * entries that caches the plines_win() result from a previous call.  Entry is
+ * zero if not computed yet.  There must be no text or setting changes since
+ * the entry is put in the cache.
+ * Returns TRUE if the position is below the last line.
+ */
+    int
+mouse_comp_pos(
+    win_T	*win,
+    int		*rowp,
+    int		*colp,
+    linenr_T	*lnump,
+    int		*plines_cache)
+{
+    int		col = *colp;
+    int		row = *rowp;
+    linenr_T	lnum;
+    int		retval = FALSE;
+    int		off;
+    int		count;
+
+#ifdef FEAT_RIGHTLEFT
+    if (win->w_p_rl)
+	col = win->w_width - 1 - col;
+#endif
+
+    lnum = win->w_topline;
+
+    while (row > 0)
+    {
+	int cache_idx = lnum - win->w_topline;
+
+	if (plines_cache != NULL && plines_cache[cache_idx] > 0)
+	    count = plines_cache[cache_idx];
+	else
+	{
+#ifdef FEAT_DIFF
+	    // Don't include filler lines in "count"
+	    if (win->w_p_diff
+# ifdef FEAT_FOLDING
+		    && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL)
+# endif
+		    )
+	    {
+		if (lnum == win->w_topline)
+		    row -= win->w_topfill;
+		else
+		    row -= diff_check_fill(win, lnum);
+		count = plines_win_nofill(win, lnum, TRUE);
+	    }
+	    else
+#endif
+		count = plines_win(win, lnum, TRUE);
+	    if (plines_cache != NULL)
+		plines_cache[cache_idx] = count;
+	}
+	if (count > row)
+	    break;	// Position is in this buffer line.
+#ifdef FEAT_FOLDING
+	(void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL);
+#endif
+	if (lnum == win->w_buffer->b_ml.ml_line_count)
+	{
+	    retval = TRUE;
+	    break;		// past end of file
+	}
+	row -= count;
+	++lnum;
+    }
+
+    if (!retval)
+    {
+	// Compute the column without wrapping.
+	off = win_col_off(win) - win_col_off2(win);
+	if (col < off)
+	    col = off;
+	col += row * (win->w_width - off);
+	// add skip column (for long wrapping line)
+	col += win->w_skipcol;
+    }
+
+    if (!win->w_p_wrap)
+	col += win->w_leftcol;
+
+    // skip line number and fold column in front of the line
+    col -= win_col_off(win);
+    if (col < 0)
+    {
+#ifdef FEAT_NETBEANS_INTG
+	netbeans_gutter_click(lnum);
+#endif
+	col = 0;
+    }
+
+    *colp = col;
+    *rowp = row;
+    *lnump = lnum;
+    return retval;
+}
+
+/*
+ * Find the window at screen position "*rowp" and "*colp".  The positions are
+ * updated to become relative to the top-left of the window.
+ * When "popup" is FAIL_POPUP and the position is in a popup window then NULL
+ * is returned.  When "popup" is IGNORE_POPUP then do not even check popup
+ * windows.
+ * Returns NULL when something is wrong.
+ */
+    win_T *
+mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
+{
+    frame_T	*fp;
+    win_T	*wp;
+
+#ifdef FEAT_TEXT_PROP
+    win_T	*pwp = NULL;
+
+    if (popup != IGNORE_POPUP)
+    {
+	popup_reset_handled();
+	while ((wp = find_next_popup(TRUE)) != NULL)
+	{
+	    if (*rowp >= wp->w_winrow && *rowp < wp->w_winrow + popup_height(wp)
+		    && *colp >= wp->w_wincol
+				    && *colp < wp->w_wincol + popup_width(wp))
+		pwp = wp;
+	}
+	if (pwp != NULL)
+	{
+	    if (popup == FAIL_POPUP)
+		return NULL;
+	    *rowp -= pwp->w_winrow;
+	    *colp -= pwp->w_wincol;
+	    return pwp;
+	}
+    }
+#endif
+
+    fp = topframe;
+    *rowp -= firstwin->w_winrow;
+    for (;;)
+    {
+	if (fp->fr_layout == FR_LEAF)
+	    break;
+	if (fp->fr_layout == FR_ROW)
+	{
+	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
+	    {
+		if (*colp < fp->fr_width)
+		    break;
+		*colp -= fp->fr_width;
+	    }
+	}
+	else    // fr_layout == FR_COL
+	{
+	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
+	    {
+		if (*rowp < fp->fr_height)
+		    break;
+		*rowp -= fp->fr_height;
+	    }
+	}
+    }
+    // When using a timer that closes a window the window might not actually
+    // exist.
+    FOR_ALL_WINDOWS(wp)
+	if (wp == fp->fr_win)
+	{
+#ifdef FEAT_MENU
+	    *rowp -= wp->w_winbar_height;
+#endif
+	    return wp;
+	}
+    return NULL;
+}
+
+#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \
+	|| defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
+	|| defined(FEAT_GUI_PHOTON) || defined(FEAT_TERM_POPUP_MENU) \
+	|| defined(PROTO)
+# define NEED_VCOL2COL
+
+/*
+ * Translate window coordinates to buffer position without any side effects
+ */
+    static int
+get_fpos_of_mouse(pos_T *mpos)
+{
+    win_T	*wp;
+    int		row = mouse_row;
+    int		col = mouse_col;
+
+    if (row < 0 || col < 0)		// check if it makes sense
+	return IN_UNKNOWN;
+
+    // find the window where the row is in
+    wp = mouse_find_win(&row, &col, FAIL_POPUP);
+    if (wp == NULL)
+	return IN_UNKNOWN;
+    // winpos and height may change in win_enter()!
+    if (row >= wp->w_height)	// In (or below) status line
+	return IN_STATUS_LINE;
+    if (col >= wp->w_width)	// In vertical separator line
+	return IN_SEP_LINE;
+
+    if (wp != curwin)
+	return IN_UNKNOWN;
+
+    // compute the position in the buffer line from the posn on the screen
+    if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum, NULL))
+	return IN_STATUS_LINE; // past bottom
+
+    mpos->col = vcol2col(wp, mpos->lnum, col);
+
+    if (mpos->col > 0)
+	--mpos->col;
+    mpos->coladd = 0;
+    return IN_BUFFER;
+}
+#endif
+
+#if defined(NEED_VCOL2COL) || defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) \
+	|| defined(PROTO)
+/*
+ * Convert a virtual (screen) column to a character column.
+ * The first column is one.
+ */
+    int
+vcol2col(win_T *wp, linenr_T lnum, int vcol)
+{
+    // try to advance to the specified column
+    int		count = 0;
+    char_u	*ptr;
+    char_u	*line;
+
+    line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
+    while (count < vcol && *ptr != NUL)
+    {
+	count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
+	MB_PTR_ADV(ptr);
+    }
+    return (int)(ptr - line);
+}
+#endif
+
+#else // FEAT_MOUSE
+
+/*
+ * Dummy implementation of setmouse() to avoid lots of #ifdefs.
+ */
+    void
+setmouse(void)
+{
+}
+
+#endif // FEAT_MOUSE
--- a/src/normal.c
+++ b/src/normal.c
@@ -30,14 +30,6 @@ static void	set_vcount_ca(cmdarg_T *cap,
 static int	nv_compare(const void *s1, const void *s2);
 static void	op_colon(oparg_T *oap);
 static void	op_function(oparg_T *oap);
-#if defined(FEAT_MOUSE)
-static void	find_start_of_word(pos_T *);
-static void	find_end_of_word(pos_T *);
-static int	get_mouse_class(char_u *p);
-#endif
-static void	prep_redo(int regname, long, int, int, int, int, int);
-static void	clearop(oparg_T *oap);
-static void	clearopbeep(oparg_T *oap);
 static void	unshift_special(cmdarg_T *cap);
 static void	may_clear_cmdline(void);
 #ifdef FEAT_CMDL_INFO
@@ -55,11 +47,6 @@ static void	nv_error(cmdarg_T *cap);
 static void	nv_help(cmdarg_T *cap);
 static void	nv_addsub(cmdarg_T *cap);
 static void	nv_page(cmdarg_T *cap);
-#ifdef FEAT_MOUSE
-static void	nv_mousescroll(cmdarg_T *cap);
-static void	nv_mouse(cmdarg_T *cap);
-#endif
-static void	nv_scroll_line(cmdarg_T *cap);
 static void	nv_zet(cmdarg_T *cap);
 #ifdef FEAT_GUI
 static void	nv_ver_scrollbar(cmdarg_T *cap);
@@ -2201,1010 +2188,6 @@ op_function(oparg_T *oap UNUSED)
 #endif
 }
 
-#if defined(FEAT_MOUSE) || defined(PROTO)
-/*
- * Do the appropriate action for the current mouse click in the current mode.
- * Not used for Command-line mode.
- *
- * Normal and Visual Mode:
- * event	 modi-	position      visual	   change   action
- *		 fier	cursor			   window
- * left press	  -	yes	    end		    yes
- * left press	  C	yes	    end		    yes	    "^]" (2)
- * left press	  S	yes	end (popup: extend) yes	    "*" (2)
- * left drag	  -	yes	start if moved	    no
- * left relse	  -	yes	start if moved	    no
- * middle press	  -	yes	 if not active	    no	    put register
- * middle press	  -	yes	 if active	    no	    yank and put
- * right press	  -	yes	start or extend	    yes
- * right press	  S	yes	no change	    yes	    "#" (2)
- * right drag	  -	yes	extend		    no
- * right relse	  -	yes	extend		    no
- *
- * Insert or Replace Mode:
- * event	 modi-	position      visual	   change   action
- *		 fier	cursor			   window
- * left press	  -	yes	(cannot be active)  yes
- * left press	  C	yes	(cannot be active)  yes	    "CTRL-O^]" (2)
- * left press	  S	yes	(cannot be active)  yes	    "CTRL-O*" (2)
- * left drag	  -	yes	start or extend (1) no	    CTRL-O (1)
- * left relse	  -	yes	start or extend (1) no	    CTRL-O (1)
- * middle press	  -	no	(cannot be active)  no	    put register
- * right press	  -	yes	start or extend	    yes	    CTRL-O
- * right press	  S	yes	(cannot be active)  yes	    "CTRL-O#" (2)
- *
- * (1) only if mouse pointer moved since press
- * (2) only if click is in same buffer
- *
- * Return TRUE if start_arrow() should be called for edit mode.
- */
-    int
-do_mouse(
-    oparg_T	*oap,		/* operator argument, can be NULL */
-    int		c,		/* K_LEFTMOUSE, etc */
-    int		dir,		/* Direction to 'put' if necessary */
-    long	count,
-    int		fixindent)	/* PUT_FIXINDENT if fixing indent necessary */
-{
-    static int	do_always = FALSE;	/* ignore 'mouse' setting next time */
-    static int	got_click = FALSE;	/* got a click some time back */
-
-    int		which_button;	/* MOUSE_LEFT, _MIDDLE or _RIGHT */
-    int		is_click;	/* If FALSE it's a drag or release event */
-    int		is_drag;	/* If TRUE it's a drag event */
-    int		jump_flags = 0;	/* flags for jump_to_mouse() */
-    pos_T	start_visual;
-    int		moved;		/* Has cursor moved? */
-    int		in_status_line;	/* mouse in status line */
-    static int	in_tab_line = FALSE; /* mouse clicked in tab line */
-    int		in_sep_line;	/* mouse in vertical separator line */
-    int		c1, c2;
-#if defined(FEAT_FOLDING)
-    pos_T	save_cursor;
-#endif
-    win_T	*old_curwin = curwin;
-    static pos_T orig_cursor;
-    colnr_T	leftcol, rightcol;
-    pos_T	end_visual;
-    int		diff;
-    int		old_active = VIsual_active;
-    int		old_mode = VIsual_mode;
-    int		regname;
-
-#if defined(FEAT_FOLDING)
-    save_cursor = curwin->w_cursor;
-#endif
-
-    /*
-     * When GUI is active, always recognize mouse events, otherwise:
-     * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
-     * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
-     * - For command line and insert mode 'mouse' is checked before calling
-     *	 do_mouse().
-     */
-    if (do_always)
-	do_always = FALSE;
-    else
-#ifdef FEAT_GUI
-	if (!gui.in_use)
-#endif
-	{
-	    if (VIsual_active)
-	    {
-		if (!mouse_has(MOUSE_VISUAL))
-		    return FALSE;
-	    }
-	    else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
-		return FALSE;
-	}
-
-    for (;;)
-    {
-	which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
-	if (is_drag)
-	{
-	    /* If the next character is the same mouse event then use that
-	     * one. Speeds up dragging the status line. */
-	    if (vpeekc() != NUL)
-	    {
-		int nc;
-		int save_mouse_row = mouse_row;
-		int save_mouse_col = mouse_col;
-
-		/* Need to get the character, peeking doesn't get the actual
-		 * one. */
-		nc = safe_vgetc();
-		if (c == nc)
-		    continue;
-		vungetc(nc);
-		mouse_row = save_mouse_row;
-		mouse_col = save_mouse_col;
-	    }
-	}
-	break;
-    }
-
-    if (c == K_MOUSEMOVE)
-    {
-	// Mouse moved without a button pressed.
-#ifdef FEAT_BEVAL_TERM
-	ui_may_remove_balloon();
-	if (p_bevalterm)
-	{
-	    profile_setlimit(p_bdlay, &bevalexpr_due);
-	    bevalexpr_due_set = TRUE;
-	}
-#endif
-#ifdef FEAT_TEXT_PROP
-	popup_handle_mouse_moved();
-#endif
-	return FALSE;
-    }
-
-#ifdef FEAT_MOUSESHAPE
-    /* May have stopped dragging the status or separator line.  The pointer is
-     * most likely still on the status or separator line. */
-    if (!is_drag && drag_status_line)
-    {
-	drag_status_line = FALSE;
-	update_mouseshape(SHAPE_IDX_STATUS);
-    }
-    if (!is_drag && drag_sep_line)
-    {
-	drag_sep_line = FALSE;
-	update_mouseshape(SHAPE_IDX_VSEP);
-    }
-#endif
-
-    /*
-     * Ignore drag and release events if we didn't get a click.
-     */
-    if (is_click)
-	got_click = TRUE;
-    else
-    {
-	if (!got_click)			/* didn't get click, ignore */
-	    return FALSE;
-	if (!is_drag)			/* release, reset got_click */
-	{
-	    got_click = FALSE;
-	    if (in_tab_line)
-	    {
-		in_tab_line = FALSE;
-		return FALSE;
-	    }
-	}
-    }
-
-    /*
-     * CTRL right mouse button does CTRL-T
-     */
-    if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
-    {
-	if (State & INSERT)
-	    stuffcharReadbuff(Ctrl_O);
-	if (count > 1)
-	    stuffnumReadbuff(count);
-	stuffcharReadbuff(Ctrl_T);
-	got_click = FALSE;		/* ignore drag&release now */
-	return FALSE;
-    }
-
-    /*
-     * CTRL only works with left mouse button
-     */
-    if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
-	return FALSE;
-
-    /*
-     * When a modifier is down, ignore drag and release events, as well as
-     * multiple clicks and the middle mouse button.
-     * Accept shift-leftmouse drags when 'mousemodel' is "popup.*".
-     */
-    if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT
-							     | MOD_MASK_META))
-	    && (!is_click
-		|| (mod_mask & MOD_MASK_MULTI_CLICK)
-		|| which_button == MOUSE_MIDDLE)
-	    && !((mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))
-		&& mouse_model_popup()
-		&& which_button == MOUSE_LEFT)
-	    && !((mod_mask & MOD_MASK_ALT)
-		&& !mouse_model_popup()
-		&& which_button == MOUSE_RIGHT)
-	    )
-	return FALSE;
-
-    /*
-     * If the button press was used as the movement command for an operator
-     * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
-     * drag/release events.
-     */
-    if (!is_click && which_button == MOUSE_MIDDLE)
-	return FALSE;
-
-    if (oap != NULL)
-	regname = oap->regname;
-    else
-	regname = 0;
-
-    /*
-     * Middle mouse button does a 'put' of the selected text
-     */
-    if (which_button == MOUSE_MIDDLE)
-    {
-	if (State == NORMAL)
-	{
-	    /*
-	     * If an operator was pending, we don't know what the user wanted
-	     * to do. Go back to normal mode: Clear the operator and beep().
-	     */
-	    if (oap != NULL && oap->op_type != OP_NOP)
-	    {
-		clearopbeep(oap);
-		return FALSE;
-	    }
-
-	    /*
-	     * If visual was active, yank the highlighted text and put it
-	     * before the mouse pointer position.
-	     * In Select mode replace the highlighted text with the clipboard.
-	     */
-	    if (VIsual_active)
-	    {
-		if (VIsual_select)
-		{
-		    stuffcharReadbuff(Ctrl_G);
-		    stuffReadbuff((char_u *)"\"+p");
-		}
-		else
-		{
-		    stuffcharReadbuff('y');
-		    stuffcharReadbuff(K_MIDDLEMOUSE);
-		}
-		do_always = TRUE;	/* ignore 'mouse' setting next time */
-		return FALSE;
-	    }
-	    /*
-	     * The rest is below jump_to_mouse()
-	     */
-	}
-
-	else if ((State & INSERT) == 0)
-	    return FALSE;
-
-	/*
-	 * Middle click in insert mode doesn't move the mouse, just insert the
-	 * contents of a register.  '.' register is special, can't insert that
-	 * with do_put().
-	 * Also paste at the cursor if the current mode isn't in 'mouse' (only
-	 * happens for the GUI).
-	 */
-	if ((State & INSERT) || !mouse_has(MOUSE_NORMAL))
-	{
-	    if (regname == '.')
-		insert_reg(regname, TRUE);
-	    else
-	    {
-#ifdef FEAT_CLIPBOARD
-		if (clip_star.available && regname == 0)
-		    regname = '*';
-#endif
-		if ((State & REPLACE_FLAG) && !yank_register_mline(regname))
-		    insert_reg(regname, TRUE);
-		else
-		{
-		    do_put(regname, BACKWARD, 1L, fixindent | PUT_CURSEND);
-
-		    /* Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r */
-		    AppendCharToRedobuff(Ctrl_R);
-		    AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O);
-		    AppendCharToRedobuff(regname == 0 ? '"' : regname);
-		}
-	    }
-	    return FALSE;
-	}
-    }
-
-    /* When dragging or button-up stay in the same window. */
-    if (!is_click)
-	jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
-
-    start_visual.lnum = 0;
-
-    /* Check for clicking in the tab page line. */
-    if (mouse_row == 0 && firstwin->w_winrow > 0)
-    {
-	if (is_drag)
-	{
-	    if (in_tab_line)
-	    {
-		c1 = TabPageIdxs[mouse_col];
-		tabpage_move(c1 <= 0 ? 9999 : c1 < tabpage_index(curtab)
-								? c1 - 1 : c1);
-	    }
-	    return FALSE;
-	}
-
-	/* click in a tab selects that tab page */
-	if (is_click
-# ifdef FEAT_CMDWIN
-		&& cmdwin_type == 0
-# endif
-		&& mouse_col < Columns)
-	{
-	    in_tab_line = TRUE;
-	    c1 = TabPageIdxs[mouse_col];
-	    if (c1 >= 0)
-	    {
-		if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
-		{
-		    /* double click opens new page */
-		    end_visual_mode();
-		    tabpage_new();
-		    tabpage_move(c1 == 0 ? 9999 : c1 - 1);
-		}
-		else
-		{
-		    /* Go to specified tab page, or next one if not clicking
-		     * on a label. */
-		    goto_tabpage(c1);
-
-		    /* It's like clicking on the status line of a window. */
-		    if (curwin != old_curwin)
-			end_visual_mode();
-		}
-	    }
-	    else
-	    {
-		tabpage_T	*tp;
-
-		/* Close the current or specified tab page. */
-		if (c1 == -999)
-		    tp = curtab;
-		else
-		    tp = find_tabpage(-c1);
-		if (tp == curtab)
-		{
-		    if (first_tabpage->tp_next != NULL)
-			tabpage_close(FALSE);
-		}
-		else if (tp != NULL)
-		    tabpage_close_other(tp, FALSE);
-	    }
-	}
-	return TRUE;
-    }
-    else if (is_drag && in_tab_line)
-    {
-	c1 = TabPageIdxs[mouse_col];
-	tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
-	return FALSE;
-    }
-
-    /*
-     * When 'mousemodel' is "popup" or "popup_setpos", translate mouse events:
-     * right button up   -> pop-up menu
-     * shift-left button -> right button
-     * alt-left button   -> alt-right button
-     */
-    if (mouse_model_popup())
-    {
-	if (which_button == MOUSE_RIGHT
-			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
-	{
-#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
-	    || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
-	    || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_PHOTON) \
-	    || defined(FEAT_TERM_POPUP_MENU)
-# ifdef FEAT_GUI
-	    if (gui.in_use)
-	    {
-#  if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
-			  || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
-		if (!is_click)
-		    /* Ignore right button release events, only shows the popup
-		     * menu on the button down event. */
-		    return FALSE;
-#  endif
-#  if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN)
-		if (is_click || is_drag)
-		    /* Ignore right button down and drag mouse events.  Windows
-		     * only shows the popup menu on the button up event. */
-		    return FALSE;
-#  endif
-	    }
-# endif
-# if defined(FEAT_GUI) && defined(FEAT_TERM_POPUP_MENU)
-	    else
-# endif
-# if defined(FEAT_TERM_POPUP_MENU)
-	    if (!is_click)
-		/* Ignore right button release events, only shows the popup
-		 * menu on the button down event. */
-		return FALSE;
-#endif
-
-	    jump_flags = 0;
-	    if (STRCMP(p_mousem, "popup_setpos") == 0)
-	    {
-		/* First set the cursor position before showing the popup
-		 * menu. */
-		if (VIsual_active)
-		{
-		    pos_T    m_pos;
-
-		    /*
-		     * set MOUSE_MAY_STOP_VIS if we are outside the
-		     * selection or the current window (might have false
-		     * negative here)
-		     */
-		    if (mouse_row < curwin->w_winrow
-			 || mouse_row
-				  > (curwin->w_winrow + curwin->w_height))
-			jump_flags = MOUSE_MAY_STOP_VIS;
-		    else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER)
-			jump_flags = MOUSE_MAY_STOP_VIS;
-		    else
-		    {
-			if ((LT_POS(curwin->w_cursor, VIsual)
-				    && (LT_POS(m_pos, curwin->w_cursor)
-					|| LT_POS(VIsual, m_pos)))
-				|| (LT_POS(VIsual, curwin->w_cursor)
-				    && (LT_POS(m_pos, VIsual)
-				      || LT_POS(curwin->w_cursor, m_pos))))
-			{
-			    jump_flags = MOUSE_MAY_STOP_VIS;
-			}
-			else if (VIsual_mode == Ctrl_V)
-			{
-			    getvcols(curwin, &curwin->w_cursor, &VIsual,
-						     &leftcol, &rightcol);
-			    getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
-			    if (m_pos.col < leftcol || m_pos.col > rightcol)
-				jump_flags = MOUSE_MAY_STOP_VIS;
-			}
-		    }
-		}
-		else
-		    jump_flags = MOUSE_MAY_STOP_VIS;
-	    }
-	    if (jump_flags)
-	    {
-		jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
-		update_curbuf(VIsual_active ? INVERTED : VALID);
-		setcursor();
-		out_flush();    /* Update before showing popup menu */
-	    }
-# ifdef FEAT_MENU
-	    show_popupmenu();
-	    got_click = FALSE;	/* ignore release events */
-# endif
-	    return (jump_flags & CURSOR_MOVED) != 0;
-#else
-	    return FALSE;
-#endif
-	}
-	if (which_button == MOUSE_LEFT
-				&& (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT)))
-	{
-	    which_button = MOUSE_RIGHT;
-	    mod_mask &= ~MOD_MASK_SHIFT;
-	}
-    }
-
-    if ((State & (NORMAL | INSERT))
-			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
-    {
-	if (which_button == MOUSE_LEFT)
-	{
-	    if (is_click)
-	    {
-		/* stop Visual mode for a left click in a window, but not when
-		 * on a status line */
-		if (VIsual_active)
-		    jump_flags |= MOUSE_MAY_STOP_VIS;
-	    }
-	    else if (mouse_has(MOUSE_VISUAL))
-		jump_flags |= MOUSE_MAY_VIS;
-	}
-	else if (which_button == MOUSE_RIGHT)
-	{
-	    if (is_click && VIsual_active)
-	    {
-		/*
-		 * Remember the start and end of visual before moving the
-		 * cursor.
-		 */
-		if (LT_POS(curwin->w_cursor, VIsual))
-		{
-		    start_visual = curwin->w_cursor;
-		    end_visual = VIsual;
-		}
-		else
-		{
-		    start_visual = VIsual;
-		    end_visual = curwin->w_cursor;
-		}
-	    }
-	    jump_flags |= MOUSE_FOCUS;
-	    if (mouse_has(MOUSE_VISUAL))
-		jump_flags |= MOUSE_MAY_VIS;
-	}
-    }
-
-    /*
-     * If an operator is pending, ignore all drags and releases until the
-     * next mouse click.
-     */
-    if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
-    {
-	got_click = FALSE;
-	oap->motion_type = MCHAR;
-    }
-
-    /* When releasing the button let jump_to_mouse() know. */
-    if (!is_click && !is_drag)
-	jump_flags |= MOUSE_RELEASED;
-
-    /*
-     * JUMP!
-     */
-    jump_flags = jump_to_mouse(jump_flags,
-			oap == NULL ? NULL : &(oap->inclusive), which_button);
-
-#ifdef FEAT_MENU
-    /* A click in the window toolbar has no side effects. */
-    if (jump_flags & MOUSE_WINBAR)
-	return FALSE;
-#endif
-    moved = (jump_flags & CURSOR_MOVED);
-    in_status_line = (jump_flags & IN_STATUS_LINE);
-    in_sep_line = (jump_flags & IN_SEP_LINE);
-
-#ifdef FEAT_NETBEANS_INTG
-    if (isNetbeansBuffer(curbuf)
-			    && !(jump_flags & (IN_STATUS_LINE | IN_SEP_LINE)))
-    {
-	int key = KEY2TERMCAP1(c);
-
-	if (key == (int)KE_LEFTRELEASE || key == (int)KE_MIDDLERELEASE
-					       || key == (int)KE_RIGHTRELEASE)
-	    netbeans_button_release(which_button);
-    }
-#endif
-
-    /* When jumping to another window, clear a pending operator.  That's a bit
-     * friendlier than beeping and not jumping to that window. */
-    if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP)
-	clearop(oap);
-
-#ifdef FEAT_FOLDING
-    if (mod_mask == 0
-	    && !is_drag
-	    && (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN))
-	    && which_button == MOUSE_LEFT)
-    {
-	/* open or close a fold at this line */
-	if (jump_flags & MOUSE_FOLD_OPEN)
-	    openFold(curwin->w_cursor.lnum, 1L);
-	else
-	    closeFold(curwin->w_cursor.lnum, 1L);
-	/* don't move the cursor if still in the same window */
-	if (curwin == old_curwin)
-	    curwin->w_cursor = save_cursor;
-    }
-#endif
-
-#if defined(FEAT_CLIPBOARD) && defined(FEAT_CMDWIN)
-    if ((jump_flags & IN_OTHER_WIN) && !VIsual_active && clip_star.available)
-    {
-	clip_modeless(which_button, is_click, is_drag);
-	return FALSE;
-    }
-#endif
-
-    /* Set global flag that we are extending the Visual area with mouse
-     * dragging; temporarily minimize 'scrolloff'. */
-    if (VIsual_active && is_drag && get_scrolloff_value())
-    {
-	/* In the very first line, allow scrolling one line */
-	if (mouse_row == 0)
-	    mouse_dragging = 2;
-	else
-	    mouse_dragging = 1;
-    }
-
-    /* When dragging the mouse above the window, scroll down. */
-    if (is_drag && mouse_row < 0 && !in_status_line)
-    {
-	scroll_redraw(FALSE, 1L);
-	mouse_row = 0;
-    }
-
-    if (start_visual.lnum)		/* right click in visual mode */
-    {
-       /* When ALT is pressed make Visual mode blockwise. */
-       if (mod_mask & MOD_MASK_ALT)
-	   VIsual_mode = Ctrl_V;
-
-	/*
-	 * In Visual-block mode, divide the area in four, pick up the corner
-	 * that is in the quarter that the cursor is in.
-	 */
-	if (VIsual_mode == Ctrl_V)
-	{
-	    getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol);
-	    if (curwin->w_curswant > (leftcol + rightcol) / 2)
-		end_visual.col = leftcol;
-	    else
-		end_visual.col = rightcol;
-	    if (curwin->w_cursor.lnum >=
-				    (start_visual.lnum + end_visual.lnum) / 2)
-		end_visual.lnum = start_visual.lnum;
-
-	    /* move VIsual to the right column */
-	    start_visual = curwin->w_cursor;	    /* save the cursor pos */
-	    curwin->w_cursor = end_visual;
-	    coladvance(end_visual.col);
-	    VIsual = curwin->w_cursor;
-	    curwin->w_cursor = start_visual;	    /* restore the cursor */
-	}
-	else
-	{
-	    /*
-	     * If the click is before the start of visual, change the start.
-	     * If the click is after the end of visual, change the end.  If
-	     * the click is inside the visual, change the closest side.
-	     */
-	    if (LT_POS(curwin->w_cursor, start_visual))
-		VIsual = end_visual;
-	    else if (LT_POS(end_visual, curwin->w_cursor))
-		VIsual = start_visual;
-	    else
-	    {
-		/* In the same line, compare column number */
-		if (end_visual.lnum == start_visual.lnum)
-		{
-		    if (curwin->w_cursor.col - start_visual.col >
-				    end_visual.col - curwin->w_cursor.col)
-			VIsual = start_visual;
-		    else
-			VIsual = end_visual;
-		}
-
-		/* In different lines, compare line number */
-		else
-		{
-		    diff = (curwin->w_cursor.lnum - start_visual.lnum) -
-				(end_visual.lnum - curwin->w_cursor.lnum);
-
-		    if (diff > 0)		/* closest to end */
-			VIsual = start_visual;
-		    else if (diff < 0)	/* closest to start */
-			VIsual = end_visual;
-		    else			/* in the middle line */
-		    {
-			if (curwin->w_cursor.col <
-					(start_visual.col + end_visual.col) / 2)
-			    VIsual = end_visual;
-			else
-			    VIsual = start_visual;
-		    }
-		}
-	    }
-	}
-    }
-    /*
-     * If Visual mode started in insert mode, execute "CTRL-O"
-     */
-    else if ((State & INSERT) && VIsual_active)
-	stuffcharReadbuff(Ctrl_O);
-
-    /*
-     * Middle mouse click: Put text before cursor.
-     */
-    if (which_button == MOUSE_MIDDLE)
-    {
-#ifdef FEAT_CLIPBOARD
-	if (clip_star.available && regname == 0)
-	    regname = '*';
-#endif
-	if (yank_register_mline(regname))
-	{
-	    if (mouse_past_bottom)
-		dir = FORWARD;
-	}
-	else if (mouse_past_eol)
-	    dir = FORWARD;
-
-	if (fixindent)
-	{
-	    c1 = (dir == BACKWARD) ? '[' : ']';
-	    c2 = 'p';
-	}
-	else
-	{
-	    c1 = (dir == FORWARD) ? 'p' : 'P';
-	    c2 = NUL;
-	}
-	prep_redo(regname, count, NUL, c1, NUL, c2, NUL);
-
-	/*
-	 * Remember where the paste started, so in edit() Insstart can be set
-	 * to this position
-	 */
-	if (restart_edit != 0)
-	    where_paste_started = curwin->w_cursor;
-	do_put(regname, dir, count, fixindent | PUT_CURSEND);
-    }
-
-#if defined(FEAT_QUICKFIX)
-    /*
-     * Ctrl-Mouse click or double click in a quickfix window jumps to the
-     * error under the mouse pointer.
-     */
-    else if (((mod_mask & MOD_MASK_CTRL)
-		|| (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
-	    && bt_quickfix(curbuf))
-    {
-	if (curwin->w_llist_ref == NULL)	/* quickfix window */
-	    do_cmdline_cmd((char_u *)".cc");
-	else					/* location list window */
-	    do_cmdline_cmd((char_u *)".ll");
-	got_click = FALSE;		/* ignore drag&release now */
-    }
-#endif
-
-    /*
-     * Ctrl-Mouse click (or double click in a help window) jumps to the tag
-     * under the mouse pointer.
-     */
-    else if ((mod_mask & MOD_MASK_CTRL) || (curbuf->b_help
-		     && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK))
-    {
-	if (State & INSERT)
-	    stuffcharReadbuff(Ctrl_O);
-	stuffcharReadbuff(Ctrl_RSB);
-	got_click = FALSE;		/* ignore drag&release now */
-    }
-
-    /*
-     * Shift-Mouse click searches for the next occurrence of the word under
-     * the mouse pointer
-     */
-    else if ((mod_mask & MOD_MASK_SHIFT))
-    {
-	if ((State & INSERT) || (VIsual_active && VIsual_select))
-	    stuffcharReadbuff(Ctrl_O);
-	if (which_button == MOUSE_LEFT)
-	    stuffcharReadbuff('*');
-	else	/* MOUSE_RIGHT */
-	    stuffcharReadbuff('#');
-    }
-
-    /* Handle double clicks, unless on status line */
-    else if (in_status_line)
-    {
-#ifdef FEAT_MOUSESHAPE
-	if ((is_drag || is_click) && !drag_status_line)
-	{
-	    drag_status_line = TRUE;
-	    update_mouseshape(-1);
-	}
-#endif
-    }
-    else if (in_sep_line)
-    {
-#ifdef FEAT_MOUSESHAPE
-	if ((is_drag || is_click) && !drag_sep_line)
-	{
-	    drag_sep_line = TRUE;
-	    update_mouseshape(-1);
-	}
-#endif
-    }
-    else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))
-	     && mouse_has(MOUSE_VISUAL))
-    {
-	if (is_click || !VIsual_active)
-	{
-	    if (VIsual_active)
-		orig_cursor = VIsual;
-	    else
-	    {
-		check_visual_highlight();
-		VIsual = curwin->w_cursor;
-		orig_cursor = VIsual;
-		VIsual_active = TRUE;
-		VIsual_reselect = TRUE;
-		/* start Select mode if 'selectmode' contains "mouse" */
-		may_start_select('o');
-		setmouse();
-	    }
-	    if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
-	    {
-		/* Double click with ALT pressed makes it blockwise. */
-		if (mod_mask & MOD_MASK_ALT)
-		    VIsual_mode = Ctrl_V;
-		else
-		    VIsual_mode = 'v';
-	    }
-	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK)
-		VIsual_mode = 'V';
-	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK)
-		VIsual_mode = Ctrl_V;
-#ifdef FEAT_CLIPBOARD
-	    /* Make sure the clipboard gets updated.  Needed because start and
-	     * end may still be the same, and the selection needs to be owned */
-	    clip_star.vmode = NUL;
-#endif
-	}
-	/*
-	 * A double click selects a word or a block.
-	 */
-	if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
-	{
-	    pos_T	*pos = NULL;
-	    int		gc;
-
-	    if (is_click)
-	    {
-		/* If the character under the cursor (skipping white space) is
-		 * not a word character, try finding a match and select a (),
-		 * {}, [], #if/#endif, etc. block. */
-		end_visual = curwin->w_cursor;
-		while (gc = gchar_pos(&end_visual), VIM_ISWHITE(gc))
-		    inc(&end_visual);
-		if (oap != NULL)
-		    oap->motion_type = MCHAR;
-		if (oap != NULL
-			&& VIsual_mode == 'v'
-			&& !vim_iswordc(gchar_pos(&end_visual))
-			&& EQUAL_POS(curwin->w_cursor, VIsual)
-			&& (pos = findmatch(oap, NUL)) != NULL)
-		{
-		    curwin->w_cursor = *pos;
-		    if (oap->motion_type == MLINE)
-			VIsual_mode = 'V';
-		    else if (*p_sel == 'e')
-		    {
-			if (LT_POS(curwin->w_cursor, VIsual))
-			    ++VIsual.col;
-			else
-			    ++curwin->w_cursor.col;
-		    }
-		}
-	    }
-
-	    if (pos == NULL && (is_click || is_drag))
-	    {
-		/* When not found a match or when dragging: extend to include
-		 * a word. */
-		if (LT_POS(curwin->w_cursor, orig_cursor))
-		{
-		    find_start_of_word(&curwin->w_cursor);
-		    find_end_of_word(&VIsual);
-		}
-		else
-		{
-		    find_start_of_word(&VIsual);
-		    if (*p_sel == 'e' && *ml_get_cursor() != NUL)
-			curwin->w_cursor.col +=
-					 (*mb_ptr2len)(ml_get_cursor());
-		    find_end_of_word(&curwin->w_cursor);
-		}
-	    }
-	    curwin->w_set_curswant = TRUE;
-	}
-	if (is_click)
-	    redraw_curbuf_later(INVERTED);	/* update the inversion */
-    }
-    else if (VIsual_active && !old_active)
-    {
-	if (mod_mask & MOD_MASK_ALT)
-	    VIsual_mode = Ctrl_V;
-	else
-	    VIsual_mode = 'v';
-    }
-
-    /* If Visual mode changed show it later. */
-    if ((!VIsual_active && old_active && mode_displayed)
-	    || (VIsual_active && p_smd && msg_silent == 0
-				 && (!old_active || VIsual_mode != old_mode)))
-	redraw_cmdline = TRUE;
-
-    return moved;
-}
-
-/*
- * Move "pos" back to the start of the word it's in.
- */
-    static void
-find_start_of_word(pos_T *pos)
-{
-    char_u	*line;
-    int		cclass;
-    int		col;
-
-    line = ml_get(pos->lnum);
-    cclass = get_mouse_class(line + pos->col);
-
-    while (pos->col > 0)
-    {
-	col = pos->col - 1;
-	col -= (*mb_head_off)(line, line + col);
-	if (get_mouse_class(line + col) != cclass)
-	    break;
-	pos->col = col;
-    }
-}
-
-/*
- * Move "pos" forward to the end of the word it's in.
- * When 'selection' is "exclusive", the position is just after the word.
- */
-    static void
-find_end_of_word(pos_T *pos)
-{
-    char_u	*line;
-    int		cclass;
-    int		col;
-
-    line = ml_get(pos->lnum);
-    if (*p_sel == 'e' && pos->col > 0)
-    {
-	--pos->col;
-	pos->col -= (*mb_head_off)(line, line + pos->col);
-    }
-    cclass = get_mouse_class(line + pos->col);
-    while (line[pos->col] != NUL)
-    {
-	col = pos->col + (*mb_ptr2len)(line + pos->col);
-	if (get_mouse_class(line + col) != cclass)
-	{
-	    if (*p_sel == 'e')
-		pos->col = col;
-	    break;
-	}
-	pos->col = col;
-    }
-}
-
-/*
- * Get class of a character for selection: same class means same word.
- * 0: blank
- * 1: punctuation groups
- * 2: normal word character
- * >2: multi-byte word character.
- */
-    static int
-get_mouse_class(char_u *p)
-{
-    int		c;
-
-    if (has_mbyte && MB_BYTE2LEN(p[0]) > 1)
-	return mb_get_class(p);
-
-    c = *p;
-    if (c == ' ' || c == '\t')
-	return 0;
-
-    if (vim_iswordc(c))
-	return 2;
-
-    /*
-     * There are a few special cases where we want certain combinations of
-     * characters to be considered as a single word.  These are things like
-     * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
-     * character is in its own class.
-     */
-    if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
-	return 1;
-    return c;
-}
-#endif /* FEAT_MOUSE */
-
 /*
  * Check if  highlighting for visual mode is possible, give a warning message
  * if not.
@@ -3531,7 +2514,7 @@ prep_redo_cmd(cmdarg_T *cap)
  * Prepare for redo of any command.
  * Note that only the last argument can be a multi-byte char.
  */
-    static void
+    void
 prep_redo(
     int	    regname,
     long    num,
@@ -3590,7 +2573,7 @@ checkclearopq(oparg_T *oap)
     return TRUE;
 }
 
-    static void
+    void
 clearop(oparg_T *oap)
 {
     oap->op_type = OP_NOP;
@@ -3599,7 +2582,7 @@ clearop(oparg_T *oap)
     oap->use_reg_one = FALSE;
 }
 
-    static void
+    void
 clearopbeep(oparg_T *oap)
 {
     clearop(oap);
@@ -4513,113 +3496,11 @@ nv_screengo(oparg_T *oap, int dir, long 
     return retval;
 }
 
-#ifdef FEAT_MOUSE
-/*
- * Mouse scroll wheel: Default action is to scroll three lines, or one page
- * when Shift or Ctrl is used.
- * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or
- * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2)
- */
-    static void
-nv_mousescroll(cmdarg_T *cap)
-{
-    win_T *old_curwin = curwin, *wp;
-
-    if (mouse_row >= 0 && mouse_col >= 0)
-    {
-	int row, col;
-
-	row = mouse_row;
-	col = mouse_col;
-
-	/* find the window at the pointer coordinates */
-	wp = mouse_find_win(&row, &col, FIND_POPUP);
-	if (wp == NULL)
-	    return;
-#ifdef FEAT_TEXT_PROP
-	if (WIN_IS_POPUP(wp) && !wp->w_has_scrollbar)
-	    return;
-#endif
-	curwin = wp;
-	curbuf = curwin->w_buffer;
-    }
-
-    if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
-    {
-# ifdef FEAT_TERMINAL
-	if (term_use_loop())
-	    /* This window is a terminal window, send the mouse event there.
-	     * Set "typed" to FALSE to avoid an endless loop. */
-	    send_keys_to_term(curbuf->b_term, cap->cmdchar, FALSE);
-	else
-# endif
-	if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-	{
-	    (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
-	}
-	else
-	{
-	    // Don't scroll more than half the window height.
-	    if (curwin->w_height < 6)
-	    {
-		cap->count1 = curwin->w_height / 2;
-		if (cap->count1 == 0)
-		    cap->count1 = 1;
-	    }
-	    else
-		cap->count1 = 3;
-	    cap->count0 = cap->count1;
-	    nv_scroll_line(cap);
-	}
-#ifdef FEAT_TEXT_PROP
-	if (WIN_IS_POPUP(curwin))
-	    popup_set_firstline(curwin);
-#endif
-    }
-# ifdef FEAT_GUI
-    else
-    {
-	/* Horizontal scroll - only allowed when 'wrap' is disabled */
-	if (!curwin->w_p_wrap)
-	{
-	    int val, step = 6;
-
-	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-		step = curwin->w_width;
-	    val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step);
-	    if (val < 0)
-		val = 0;
-
-	    gui_do_horiz_scroll(val, TRUE);
-	}
-    }
-# endif
-# ifdef FEAT_SYN_HL
-    if (curwin != old_curwin && curwin->w_p_cul)
-	redraw_for_cursorline(curwin);
-# endif
-
-    curwin->w_redr_status = TRUE;
-
-    curwin = old_curwin;
-    curbuf = curwin->w_buffer;
-}
-
-/*
- * Mouse clicks and drags.
- */
-    static void
-nv_mouse(cmdarg_T *cap)
-{
-    (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0);
-}
-#endif
-
 /*
  * Handle CTRL-E and CTRL-Y commands: scroll a line up or down.
  * cap->arg must be TRUE for CTRL-E.
  */
-    static void
+    void
 nv_scroll_line(cmdarg_T *cap)
 {
     if (!checkclearop(cap->oap))
@@ -7572,9 +6453,7 @@ nv_visual(cmdarg_T *cap)
 	    if (!cap->arg)
 		/* start Select mode when 'selectmode' contains "cmd" */
 		may_start_select('c');
-#ifdef FEAT_MOUSE
 	    setmouse();
-#endif
 	    if (p_smd && msg_silent == 0)
 		redraw_cmdline = TRUE;	    /* show visual mode later */
 	    /*
@@ -7687,9 +6566,7 @@ n_start_visual_mode(int c)
     foldAdjustVisual();
 #endif
 
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 #ifdef FEAT_CONCEAL
     /* Check for redraw after changing the state. */
     conceal_check_cursor_line();
@@ -7854,9 +6731,7 @@ nv_g_cmd(cmdarg_T *cap)
 		VIsual_select = TRUE;
 	    else
 		may_start_select('c');
-#ifdef FEAT_MOUSE
 	    setmouse();
-#endif
 #ifdef FEAT_CLIPBOARD
 	    /* Make sure the clipboard gets updated.  Needed because start and
 	     * end are still the same, and the selection needs to be owned */
--- a/src/proto.h
+++ b/src/proto.h
@@ -175,6 +175,7 @@ char_u *vim_strpbrk(char_u *s, char_u *c
 /* Use our own qsort(), don't define the prototype when not used. */
 void qsort(void *base, size_t elm_count, size_t elm_size, int (*cmp)(const void *, const void *));
 #endif
+# include "mouse.pro"
 # include "move.pro"
 # include "mbyte.pro"
 # include "normal.pro"
--- a/src/proto/edit.pro
+++ b/src/proto/edit.pro
@@ -7,6 +7,7 @@ char_u *prompt_text(void);
 int prompt_curpos_editable(void);
 void edit_unputchar(void);
 void display_dollar(colnr_T col);
+void undisplay_dollar(void);
 void change_indent(int type, int amount, int round, int replaced, int call_changed_bytes);
 void truncate_spaces(char_u *line);
 void backspace_until_column(int col);
@@ -36,6 +37,7 @@ void ins_horscroll(void);
 int ins_eol(int c);
 int ins_copychar(linenr_T lnum);
 colnr_T get_nolist_virtcol(void);
-int can_cindent_get(void);
+int get_can_cindent(void);
+void set_can_cindent(int val);
 int ins_apply_autocmds(event_T event);
 /* vim: set ft=c : */
--- a/src/proto/misc1.pro
+++ b/src/proto/misc1.pro
@@ -23,7 +23,6 @@ int inindent(int extra);
 char_u *skip_to_option_part(char_u *p);
 void check_status(buf_T *buf);
 int ask_yesno(char_u *str, int direct);
-int is_mouse_key(int c);
 void f_mode(typval_T *argvars, typval_T *rettv);
 void f_state(typval_T *argvars, typval_T *rettv);
 int get_keystroke(void);
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -74,8 +74,6 @@ int extract_modifiers(int key, int *modp
 int find_special_key_in_table(int c);
 int get_special_key_code(char_u *name);
 char_u *get_key_name(int i);
-int get_mouse_button(int code, int *is_click, int *is_drag);
-int get_pseudo_mouse_code(int button, int is_click, int is_drag);
 int get_fileformat(buf_T *buf);
 int get_fileformat_force(buf_T *buf, exarg_T *eap);
 void set_fileformat(int t, int opt_flags);
new file mode 100644
--- /dev/null
+++ b/src/proto/mouse.pro
@@ -0,0 +1,19 @@
+/* mouse.c */
+int do_mouse(oparg_T *oap, int c, int dir, long count, int fixindent);
+void ins_mouse(int c);
+void ins_mousescroll(int dir);
+int is_mouse_key(int c);
+int get_mouse_button(int code, int *is_click, int *is_drag);
+int get_pseudo_mouse_code(int button, int is_click, int is_drag);
+void set_mouse_termcode(int n, char_u *s);
+void del_mouse_termcode(int n);
+void setmouse(void);
+int mouse_has(int c);
+int mouse_model_popup(void);
+int jump_to_mouse(int flags, int *inclusive, int which_button);
+void nv_mousescroll(cmdarg_T *cap);
+void nv_mouse(cmdarg_T *cap);
+int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump, int *plines_cache);
+win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup);
+int vcol2col(win_T *wp, linenr_T lnum, int vcol);
+/* vim: set ft=c : */
--- a/src/proto/normal.pro
+++ b/src/proto/normal.pro
@@ -2,13 +2,15 @@
 void init_normal_cmds(void);
 void normal_cmd(oparg_T *oap, int toplevel);
 void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank);
-int do_mouse(oparg_T *oap, int c, int dir, long count, int fixindent);
 void check_visual_highlight(void);
 void end_visual_mode(void);
 void reset_VIsual_and_resel(void);
 void reset_VIsual(void);
 int find_ident_under_cursor(char_u **text, int find_type);
 int find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **text, int *textcol, int find_type);
+void prep_redo(int regname, long, int, int, int, int, int);
+void clearop(oparg_T *oap);
+void clearopbeep(oparg_T *oap);
 void clear_showcmd(void);
 int add_to_showcmd(int c);
 void add_to_showcmd_c(int c);
@@ -17,6 +19,7 @@ void pop_showcmd(void);
 void do_check_scrollbind(int check);
 void check_scrollbind(linenr_T topline_diff, long leftcol_diff);
 int find_decl(char_u *ptr, int len, int locally, int thisblock, int flags_arg);
+void nv_scroll_line(cmdarg_T *cap);
 void scroll_redraw(int up, long count);
 void handle_tabmenu(void);
 void do_nv_ident(int c1, int c2);
--- a/src/proto/term.pro
+++ b/src/proto/term.pro
@@ -2,8 +2,6 @@
 guicolor_T termgui_get_color(char_u *name);
 guicolor_T termgui_mch_get_rgb(guicolor_T color);
 int set_termname(char_u *term);
-void set_mouse_termcode(int n, char_u *s);
-void del_mouse_termcode(int n);
 void getlinecol(long *cp, long *rp);
 int add_termcap_entry(char_u *name, int force);
 int term_is_8bit(char_u *name);
@@ -47,9 +45,6 @@ void may_req_termresponse(void);
 void may_req_ambiguous_char_width(void);
 void may_req_bg_color(void);
 int swapping_screen(void);
-void setmouse(void);
-int mouse_has(int c);
-int mouse_model_popup(void);
 void scroll_start(void);
 void cursor_on_force(void);
 void cursor_on(void);
@@ -64,6 +59,7 @@ void clear_termcodes(void);
 void add_termcode(char_u *name, char_u *string, int flags);
 char_u *find_termcode(char_u *name);
 char_u *get_termcode(int i);
+void del_termcode(char_u *name);
 void set_mouse_topline(win_T *wp);
 int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen);
 void term_get_fg_color(char_u *r, char_u *g, char_u *b);
--- a/src/proto/ui.pro
+++ b/src/proto/ui.pro
@@ -60,11 +60,6 @@ void clip_x11_lose_selection(Widget mySh
 int clip_x11_own_selection(Widget myShell, Clipboard_T *cbd);
 void clip_x11_set_selection(Clipboard_T *cbd);
 void yank_cut_buffer0(Display *dpy, Clipboard_T *cbd);
-int jump_to_mouse(int flags, int *inclusive, int which_button);
-int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump, int *plines_cache);
-win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup);
-int get_fpos_of_mouse(pos_T *mpos);
-int vcol2col(win_T *wp, linenr_T lnum, int vcol);
 void ui_focus_change(int in_focus);
 void im_save_status(long *psave);
 /* vim: set ft=c : */
--- a/src/search.c
+++ b/src/search.c
@@ -4803,9 +4803,7 @@ current_search(
 #endif
 
     may_start_select('c');
-#ifdef FEAT_MOUSE
     setmouse();
-#endif
 #ifdef FEAT_CLIPBOARD
     /* Make sure the clipboard gets updated.  Needed because start and
      * end are still the same, and the selection needs to be owned */
--- a/src/term.c
+++ b/src/term.c
@@ -87,7 +87,6 @@ static void check_for_codes_from_term(vo
 		|| defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE)))
 static int get_bytes_from_buf(char_u *, char_u *, int);
 #endif
-static void del_termcode(char_u *name);
 static void del_termcode_idx(int idx);
 static int find_term_bykeys(char_u *src);
 static int term_is_builtin(char_u *name);
@@ -2048,9 +2047,7 @@ set_termname(char_u *term)
     if (starting != NO_SCREEN)
     {
 	starttermcap();		/* may change terminal mode */
-#ifdef FEAT_MOUSE
 	setmouse();		/* may start using the mouse */
-#endif
 #ifdef FEAT_TITLE
 	maketitle();		/* may display window title */
 #endif
@@ -2101,126 +2098,6 @@ set_termname(char_u *term)
     return OK;
 }
 
-#if defined(FEAT_MOUSE) || defined(PROTO)
-
-# ifdef FEAT_MOUSE_TTY
-#  define HMT_NORMAL	1
-#  define HMT_NETTERM	2
-#  define HMT_DEC	4
-#  define HMT_JSBTERM	8
-#  define HMT_PTERM	16
-#  define HMT_URXVT	32
-#  define HMT_GPM	64
-#  define HMT_SGR	128
-#  define HMT_SGR_REL	256
-static int has_mouse_termcode = 0;
-# endif
-
-# if (!defined(UNIX) || defined(FEAT_MOUSE_TTY)) || defined(PROTO)
-    void
-set_mouse_termcode(
-    int		n,	/* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */
-    char_u	*s)
-{
-    char_u	name[2];
-
-    name[0] = n;
-    name[1] = KE_FILLER;
-    add_termcode(name, s, FALSE);
-#  ifdef FEAT_MOUSE_TTY
-#   ifdef FEAT_MOUSE_JSB
-    if (n == KS_JSBTERM_MOUSE)
-	has_mouse_termcode |= HMT_JSBTERM;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_NET
-    if (n == KS_NETTERM_MOUSE)
-	has_mouse_termcode |= HMT_NETTERM;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_DEC
-    if (n == KS_DEC_MOUSE)
-	has_mouse_termcode |= HMT_DEC;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_PTERM
-    if (n == KS_PTERM_MOUSE)
-	has_mouse_termcode |= HMT_PTERM;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_URXVT
-    if (n == KS_URXVT_MOUSE)
-	has_mouse_termcode |= HMT_URXVT;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_GPM
-    if (n == KS_GPM_MOUSE)
-	has_mouse_termcode |= HMT_GPM;
-    else
-#   endif
-    if (n == KS_SGR_MOUSE)
-	has_mouse_termcode |= HMT_SGR;
-    else if (n == KS_SGR_MOUSE_RELEASE)
-	has_mouse_termcode |= HMT_SGR_REL;
-    else
-	has_mouse_termcode |= HMT_NORMAL;
-#  endif
-}
-# endif
-
-# if ((defined(UNIX) || defined(VMS)) \
-	&& defined(FEAT_MOUSE_TTY)) || defined(PROTO)
-    void
-del_mouse_termcode(
-    int		n)	/* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */
-{
-    char_u	name[2];
-
-    name[0] = n;
-    name[1] = KE_FILLER;
-    del_termcode(name);
-#  ifdef FEAT_MOUSE_TTY
-#   ifdef FEAT_MOUSE_JSB
-    if (n == KS_JSBTERM_MOUSE)
-	has_mouse_termcode &= ~HMT_JSBTERM;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_NET
-    if (n == KS_NETTERM_MOUSE)
-	has_mouse_termcode &= ~HMT_NETTERM;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_DEC
-    if (n == KS_DEC_MOUSE)
-	has_mouse_termcode &= ~HMT_DEC;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_PTERM
-    if (n == KS_PTERM_MOUSE)
-	has_mouse_termcode &= ~HMT_PTERM;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_URXVT
-    if (n == KS_URXVT_MOUSE)
-	has_mouse_termcode &= ~HMT_URXVT;
-    else
-#   endif
-#   ifdef FEAT_MOUSE_GPM
-    if (n == KS_GPM_MOUSE)
-	has_mouse_termcode &= ~HMT_GPM;
-    else
-#   endif
-    if (n == KS_SGR_MOUSE)
-	has_mouse_termcode &= ~HMT_SGR;
-    else if (n == KS_SGR_MOUSE_RELEASE)
-	has_mouse_termcode &= ~HMT_SGR_REL;
-    else
-	has_mouse_termcode &= ~HMT_NORMAL;
-#  endif
-}
-# endif
-#endif
-
 #ifdef HAVE_TGETENT
 /*
  * Call tgetent()
@@ -3574,10 +3451,8 @@ settmode(int tmode)
 	    out_flush();
 	    mch_settmode(tmode);	// machine specific function
 	    cur_tmode = tmode;
-#ifdef FEAT_MOUSE
 	    if (tmode == TMODE_RAW)
 		setmouse();		// may switch mouse on
-#endif
 	    out_flush();
 	}
 #ifdef FEAT_TERMRESPONSE
@@ -3811,94 +3686,6 @@ swapping_screen(void)
     return (full_screen && *T_TI != NUL);
 }
 
-#if defined(FEAT_MOUSE) || defined(PROTO)
-/*
- * setmouse() - switch mouse on/off depending on current mode and 'mouse'
- */
-    void
-setmouse(void)
-{
-# ifdef FEAT_MOUSE_TTY
-    int	    checkfor;
-# endif
-
-# ifdef FEAT_MOUSESHAPE
-    update_mouseshape(-1);
-# endif
-
-# ifdef FEAT_MOUSE_TTY /* Should be outside proc, but may break MOUSESHAPE */
-#  ifdef FEAT_GUI
-    /* In the GUI the mouse is always enabled. */
-    if (gui.in_use)
-	return;
-#  endif
-    /* be quick when mouse is off */
-    if (*p_mouse == NUL || has_mouse_termcode == 0)
-	return;
-
-    /* don't switch mouse on when not in raw mode (Ex mode) */
-    if (cur_tmode != TMODE_RAW)
-    {
-	mch_setmouse(FALSE);
-	return;
-    }
-
-    if (VIsual_active)
-	checkfor = MOUSE_VISUAL;
-    else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE)
-	checkfor = MOUSE_RETURN;
-    else if (State & INSERT)
-	checkfor = MOUSE_INSERT;
-    else if (State & CMDLINE)
-	checkfor = MOUSE_COMMAND;
-    else if (State == CONFIRM || State == EXTERNCMD)
-	checkfor = ' '; /* don't use mouse for ":confirm" or ":!cmd" */
-    else
-	checkfor = MOUSE_NORMAL;    /* assume normal mode */
-
-    if (mouse_has(checkfor))
-	mch_setmouse(TRUE);
-    else
-	mch_setmouse(FALSE);
-# endif
-}
-
-/*
- * Return TRUE if
- * - "c" is in 'mouse', or
- * - 'a' is in 'mouse' and "c" is in MOUSE_A, or
- * - the current buffer is a help file and 'h' is in 'mouse' and we are in a
- *   normal editing mode (not at hit-return message).
- */
-    int
-mouse_has(int c)
-{
-    char_u	*p;
-
-    for (p = p_mouse; *p; ++p)
-	switch (*p)
-	{
-	    case 'a': if (vim_strchr((char_u *)MOUSE_A, c) != NULL)
-			  return TRUE;
-		      break;
-	    case MOUSE_HELP: if (c != MOUSE_RETURN && curbuf->b_help)
-				 return TRUE;
-			     break;
-	    default: if (c == *p) return TRUE; break;
-	}
-    return FALSE;
-}
-
-/*
- * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos".
- */
-    int
-mouse_model_popup(void)
-{
-    return (p_mousem[0] == 'p');
-}
-#endif
-
 /*
  * By outputting the 'cursor very visible' termcap code, for some windowed
  * terminals this makes the screen scrolled to the correct position.
@@ -4307,7 +4094,7 @@ get_termcode(int i)
     return &termcodes[i].name[0];
 }
 
-    static void
+    void
 del_termcode(char_u *name)
 {
     int	    i;
@@ -5298,23 +5085,23 @@ check_termcode(
 		 * are decimal instead of bytes.
 		 *
 		 * \033[%d;%d;%dM
-		 *		  ^-- row
-		 *	       ^----- column
-		 *	    ^-------- code
+		 *	       ^-- row
+		 *	    ^----- column
+		 *	 ^-------- code
 		 *
 		 * SGR 1006 mouse reporting mode:
 		 * Almost identical to xterm mouse mode, except the values
 		 * are decimal instead of bytes.
 		 *
 		 * \033[<%d;%d;%dM
-		 *		   ^-- row
-		 *	        ^----- column
-		 *	     ^-------- code
+		 *	       ^-- row
+		 *	    ^----- column
+		 *	 ^-------- code
 		 *
 		 * \033[<%d;%d;%dm        : mouse release event
-		 *		   ^-- row
-		 *	        ^----- column
-		 *	     ^-------- code
+		 *	       ^-- row
+		 *	    ^----- column
+		 *	 ^-------- code
 		 */
 		p = modifiers_start;
 		if (p == NULL)
--- a/src/ui.c
+++ b/src/ui.c
@@ -2917,797 +2917,6 @@ yank_cut_buffer0(Display *dpy, Clipboard
 }
 #endif
 
-#if defined(FEAT_MOUSE) || defined(PROTO)
-
-/*
- * Move the cursor to the specified row and column on the screen.
- * Change current window if necessary.	Returns an integer with the
- * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
- *
- * The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
- * The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
- *
- * If flags has MOUSE_FOCUS, then the current window will not be changed, and
- * if the mouse is outside the window then the text will scroll, or if the
- * mouse was previously on a status line, then the status line may be dragged.
- *
- * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
- * cursor is moved unless the cursor was on a status line.
- * This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
- * IN_SEP_LINE depending on where the cursor was clicked.
- *
- * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
- * the mouse is on the status line of the same window.
- *
- * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
- * the last call.
- *
- * If flags has MOUSE_SETPOS, nothing is done, only the current position is
- * remembered.
- */
-    int
-jump_to_mouse(
-    int		flags,
-    int		*inclusive,	/* used for inclusive operator, can be NULL */
-    int		which_button)	/* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */
-{
-    static int	on_status_line = 0;	/* #lines below bottom of window */
-    static int	on_sep_line = 0;	/* on separator right of window */
-#ifdef FEAT_MENU
-    static int  in_winbar = FALSE;
-#endif
-#ifdef FEAT_TEXT_PROP
-    static int   in_popup_win = FALSE;
-    static win_T *click_in_popup_win = NULL;
-#endif
-    static int	prev_row = -1;
-    static int	prev_col = -1;
-    static win_T *dragwin = NULL;	/* window being dragged */
-    static int	did_drag = FALSE;	/* drag was noticed */
-
-    win_T	*wp, *old_curwin;
-    pos_T	old_cursor;
-    int		count;
-    int		first;
-    int		row = mouse_row;
-    int		col = mouse_col;
-#ifdef FEAT_FOLDING
-    int		mouse_char;
-#endif
-
-    mouse_past_bottom = FALSE;
-    mouse_past_eol = FALSE;
-
-    if (flags & MOUSE_RELEASED)
-    {
-	/* On button release we may change window focus if positioned on a
-	 * status line and no dragging happened. */
-	if (dragwin != NULL && !did_drag)
-	    flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
-	dragwin = NULL;
-	did_drag = FALSE;
-#ifdef FEAT_TEXT_PROP
-	if (click_in_popup_win != NULL && popup_dragwin == NULL)
-	    popup_close_for_mouse_click(click_in_popup_win);
-
-	popup_dragwin = NULL;
-	click_in_popup_win = NULL;
-#endif
-    }
-
-    if ((flags & MOUSE_DID_MOVE)
-	    && prev_row == mouse_row
-	    && prev_col == mouse_col)
-    {
-retnomove:
-	/* before moving the cursor for a left click which is NOT in a status
-	 * line, stop Visual mode */
-	if (on_status_line)
-	    return IN_STATUS_LINE;
-	if (on_sep_line)
-	    return IN_SEP_LINE;
-#ifdef FEAT_MENU
-	if (in_winbar)
-	{
-	    /* A quick second click may arrive as a double-click, but we use it
-	     * as a second click in the WinBar. */
-	    if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED))
-	    {
-		wp = mouse_find_win(&row, &col, FAIL_POPUP);
-		if (wp == NULL)
-		    return IN_UNKNOWN;
-		winbar_click(wp, col);
-	    }
-	    return IN_OTHER_WIN | MOUSE_WINBAR;
-	}
-#endif
-	if (flags & MOUSE_MAY_STOP_VIS)
-	{
-	    end_visual_mode();
-	    redraw_curbuf_later(INVERTED);	/* delete the inversion */
-	}
-#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
-	// Continue a modeless selection in another window.
-	if (cmdwin_type != 0 && row < curwin->w_winrow)
-	    return IN_OTHER_WIN;
-#endif
-#ifdef FEAT_TEXT_PROP
-	// Continue a modeless selection in a popup window or dragging it.
-	if (in_popup_win)
-	{
-	    click_in_popup_win = NULL;  // don't close it on release
-	    if (popup_dragwin != NULL)
-	    {
-		// dragging a popup window
-		popup_drag(popup_dragwin);
-		return IN_UNKNOWN;
-	    }
-	    return IN_OTHER_WIN;
-	}
-#endif
-	return IN_BUFFER;
-    }
-
-    prev_row = mouse_row;
-    prev_col = mouse_col;
-
-    if (flags & MOUSE_SETPOS)
-	goto retnomove;				/* ugly goto... */
-
-#ifdef FEAT_FOLDING
-    /* Remember the character under the mouse, it might be a '-' or '+' in the
-     * fold column. */
-    if (row >= 0 && row < Rows && col >= 0 && col <= Columns
-						       && ScreenLines != NULL)
-	mouse_char = ScreenLines[LineOffset[row] + col];
-    else
-	mouse_char = ' ';
-#endif
-
-    old_curwin = curwin;
-    old_cursor = curwin->w_cursor;
-
-    if (!(flags & MOUSE_FOCUS))
-    {
-	if (row < 0 || col < 0)			// check if it makes sense
-	    return IN_UNKNOWN;
-
-	// find the window where the row is in and adjust "row" and "col" to be
-	// relative to top-left of the window
-	wp = mouse_find_win(&row, &col, FIND_POPUP);
-	if (wp == NULL)
-	    return IN_UNKNOWN;
-	dragwin = NULL;
-
-#ifdef FEAT_TEXT_PROP
-	// Click in a popup window may start dragging or modeless selection,
-	// but not much else.
-	if (WIN_IS_POPUP(wp))
-	{
-	    on_sep_line = 0;
-	    in_popup_win = TRUE;
-	    if (which_button == MOUSE_LEFT && popup_close_if_on_X(wp, row, col))
-	    {
-		return IN_UNKNOWN;
-	    }
-	    else if ((wp->w_popup_flags & (POPF_DRAG | POPF_RESIZE))
-					      && popup_on_border(wp, row, col))
-	    {
-		popup_dragwin = wp;
-		popup_start_drag(wp, row, col);
-		return IN_UNKNOWN;
-	    }
-	    // Only close on release, otherwise it's not possible to drag or do
-	    // modeless selection.
-	    else if (wp->w_popup_close == POPCLOSE_CLICK
-		    && which_button == MOUSE_LEFT)
-	    {
-		click_in_popup_win = wp;
-	    }
-	    else if (which_button == MOUSE_LEFT)
-		// If the click is in the scrollbar, may scroll up/down.
-		popup_handle_scrollbar_click(wp, row, col);
-# ifdef FEAT_CLIPBOARD
-	    return IN_OTHER_WIN;
-# else
-	    return IN_UNKNOWN;
-# endif
-	}
-	in_popup_win = FALSE;
-	popup_dragwin = NULL;
-#endif
-#ifdef FEAT_MENU
-	if (row == -1)
-	{
-	    /* A click in the window toolbar does not enter another window or
-	     * change Visual highlighting. */
-	    winbar_click(wp, col);
-	    in_winbar = TRUE;
-	    return IN_OTHER_WIN | MOUSE_WINBAR;
-	}
-	in_winbar = FALSE;
-#endif
-
-	/*
-	 * winpos and height may change in win_enter()!
-	 */
-	if (row >= wp->w_height)		/* In (or below) status line */
-	{
-	    on_status_line = row - wp->w_height + 1;
-	    dragwin = wp;
-	}
-	else
-	    on_status_line = 0;
-	if (col >= wp->w_width)		/* In separator line */
-	{
-	    on_sep_line = col - wp->w_width + 1;
-	    dragwin = wp;
-	}
-	else
-	    on_sep_line = 0;
-
-	/* The rightmost character of the status line might be a vertical
-	 * separator character if there is no connecting window to the right. */
-	if (on_status_line && on_sep_line)
-	{
-	    if (stl_connected(wp))
-		on_sep_line = 0;
-	    else
-		on_status_line = 0;
-	}
-
-	/* Before jumping to another buffer, or moving the cursor for a left
-	 * click, stop Visual mode. */
-	if (VIsual_active
-		&& (wp->w_buffer != curwin->w_buffer
-		    || (!on_status_line && !on_sep_line
-#ifdef FEAT_FOLDING
-			&& (
-# ifdef FEAT_RIGHTLEFT
-			    wp->w_p_rl ? col < wp->w_width - wp->w_p_fdc :
-# endif
-			    col >= wp->w_p_fdc
-# ifdef FEAT_CMDWIN
-				  + (cmdwin_type == 0 && wp == curwin ? 0 : 1)
-# endif
-			    )
-#endif
-			&& (flags & MOUSE_MAY_STOP_VIS))))
-	{
-	    end_visual_mode();
-	    redraw_curbuf_later(INVERTED);	/* delete the inversion */
-	}
-#ifdef FEAT_CMDWIN
-	if (cmdwin_type != 0 && wp != curwin)
-	{
-	    /* A click outside the command-line window: Use modeless
-	     * selection if possible.  Allow dragging the status lines. */
-	    on_sep_line = 0;
-# ifdef FEAT_CLIPBOARD
-	    if (on_status_line)
-		return IN_STATUS_LINE;
-	    return IN_OTHER_WIN;
-# else
-	    row = 0;
-	    col += wp->w_wincol;
-	    wp = curwin;
-# endif
-	}
-#endif
-	/* Only change window focus when not clicking on or dragging the
-	 * status line.  Do change focus when releasing the mouse button
-	 * (MOUSE_FOCUS was set above if we dragged first). */
-	if (dragwin == NULL || (flags & MOUSE_RELEASED))
-	    win_enter(wp, TRUE);		/* can make wp invalid! */
-
-	if (curwin != old_curwin)
-	{
-#ifdef CHECK_DOUBLE_CLICK
-	    /* set topline, to be able to check for double click ourselves */
-	    set_mouse_topline(curwin);
-#endif
-#ifdef FEAT_TERMINAL
-	    /* when entering a terminal window may change state */
-	    term_win_entered();
-#endif
-	}
-	if (on_status_line)			/* In (or below) status line */
-	{
-	    /* Don't use start_arrow() if we're in the same window */
-	    if (curwin == old_curwin)
-		return IN_STATUS_LINE;
-	    else
-		return IN_STATUS_LINE | CURSOR_MOVED;
-	}
-	if (on_sep_line)			/* In (or below) status line */
-	{
-	    /* Don't use start_arrow() if we're in the same window */
-	    if (curwin == old_curwin)
-		return IN_SEP_LINE;
-	    else
-		return IN_SEP_LINE | CURSOR_MOVED;
-	}
-
-	curwin->w_cursor.lnum = curwin->w_topline;
-#ifdef FEAT_GUI
-	/* remember topline, needed for double click */
-	gui_prev_topline = curwin->w_topline;
-# ifdef FEAT_DIFF
-	gui_prev_topfill = curwin->w_topfill;
-# endif
-#endif
-    }
-    else if (on_status_line && which_button == MOUSE_LEFT)
-    {
-	if (dragwin != NULL)
-	{
-	    /* Drag the status line */
-	    count = row - dragwin->w_winrow - dragwin->w_height + 1
-							     - on_status_line;
-	    win_drag_status_line(dragwin, count);
-	    did_drag |= count;
-	}
-	return IN_STATUS_LINE;			/* Cursor didn't move */
-    }
-    else if (on_sep_line && which_button == MOUSE_LEFT)
-    {
-	if (dragwin != NULL)
-	{
-	    /* Drag the separator column */
-	    count = col - dragwin->w_wincol - dragwin->w_width + 1
-								- on_sep_line;
-	    win_drag_vsep_line(dragwin, count);
-	    did_drag |= count;
-	}
-	return IN_SEP_LINE;			/* Cursor didn't move */
-    }
-#ifdef FEAT_MENU
-    else if (in_winbar)
-    {
-	/* After a click on the window toolbar don't start Visual mode. */
-	return IN_OTHER_WIN | MOUSE_WINBAR;
-    }
-#endif
-    else /* keep_window_focus must be TRUE */
-    {
-	/* before moving the cursor for a left click, stop Visual mode */
-	if (flags & MOUSE_MAY_STOP_VIS)
-	{
-	    end_visual_mode();
-	    redraw_curbuf_later(INVERTED);	/* delete the inversion */
-	}
-
-#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
-	/* Continue a modeless selection in another window. */
-	if (cmdwin_type != 0 && row < curwin->w_winrow)
-	    return IN_OTHER_WIN;
-#endif
-#ifdef FEAT_TEXT_PROP
-	if (in_popup_win)
-	{
-	    if (popup_dragwin != NULL)
-	    {
-		// dragging a popup window
-		popup_drag(popup_dragwin);
-		return IN_UNKNOWN;
-	    }
-	    // continue a modeless selection in a popup window
-	    click_in_popup_win = NULL;
-	    return IN_OTHER_WIN;
-	}
-#endif
-
-	row -= W_WINROW(curwin);
-	col -= curwin->w_wincol;
-
-	/*
-	 * When clicking beyond the end of the window, scroll the screen.
-	 * Scroll by however many rows outside the window we are.
-	 */
-	if (row < 0)
-	{
-	    count = 0;
-	    for (first = TRUE; curwin->w_topline > 1; )
-	    {
-#ifdef FEAT_DIFF
-		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
-		    ++count;
-		else
-#endif
-		    count += plines(curwin->w_topline - 1);
-		if (!first && count > -row)
-		    break;
-		first = FALSE;
-#ifdef FEAT_FOLDING
-		(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
-#endif
-#ifdef FEAT_DIFF
-		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
-		    ++curwin->w_topfill;
-		else
-#endif
-		{
-		    --curwin->w_topline;
-#ifdef FEAT_DIFF
-		    curwin->w_topfill = 0;
-#endif
-		}
-	    }
-#ifdef FEAT_DIFF
-	    check_topfill(curwin, FALSE);
-#endif
-	    curwin->w_valid &=
-		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
-	    redraw_later(VALID);
-	    row = 0;
-	}
-	else if (row >= curwin->w_height)
-	{
-	    count = 0;
-	    for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; )
-	    {
-#ifdef FEAT_DIFF
-		if (curwin->w_topfill > 0)
-		    ++count;
-		else
-#endif
-		    count += plines(curwin->w_topline);
-		if (!first && count > row - curwin->w_height + 1)
-		    break;
-		first = FALSE;
-#ifdef FEAT_FOLDING
-		if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
-			&& curwin->w_topline == curbuf->b_ml.ml_line_count)
-		    break;
-#endif
-#ifdef FEAT_DIFF
-		if (curwin->w_topfill > 0)
-		    --curwin->w_topfill;
-		else
-#endif
-		{
-		    ++curwin->w_topline;
-#ifdef FEAT_DIFF
-		    curwin->w_topfill =
-				   diff_check_fill(curwin, curwin->w_topline);
-#endif
-		}
-	    }
-#ifdef FEAT_DIFF
-	    check_topfill(curwin, FALSE);
-#endif
-	    redraw_later(VALID);
-	    curwin->w_valid &=
-		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
-	    row = curwin->w_height - 1;
-	}
-	else if (row == 0)
-	{
-	    /* When dragging the mouse, while the text has been scrolled up as
-	     * far as it goes, moving the mouse in the top line should scroll
-	     * the text down (done later when recomputing w_topline). */
-	    if (mouse_dragging > 0
-		    && curwin->w_cursor.lnum
-				       == curwin->w_buffer->b_ml.ml_line_count
-		    && curwin->w_cursor.lnum == curwin->w_topline)
-		curwin->w_valid &= ~(VALID_TOPLINE);
-	}
-    }
-
-#ifdef FEAT_FOLDING
-    /* Check for position outside of the fold column. */
-    if (
-# ifdef FEAT_RIGHTLEFT
-	    curwin->w_p_rl ? col < curwin->w_width - curwin->w_p_fdc :
-# endif
-	    col >= curwin->w_p_fdc
-#  ifdef FEAT_CMDWIN
-				+ (cmdwin_type == 0 ? 0 : 1)
-#  endif
-       )
-	mouse_char = ' ';
-#endif
-
-    /* compute the position in the buffer line from the posn on the screen */
-    if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum, NULL))
-	mouse_past_bottom = TRUE;
-
-    /* Start Visual mode before coladvance(), for when 'sel' != "old" */
-    if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
-    {
-	check_visual_highlight();
-	VIsual = old_cursor;
-	VIsual_active = TRUE;
-	VIsual_reselect = TRUE;
-	/* if 'selectmode' contains "mouse", start Select mode */
-	may_start_select('o');
-	setmouse();
-	if (p_smd && msg_silent == 0)
-	    redraw_cmdline = TRUE;	/* show visual mode later */
-    }
-
-    curwin->w_curswant = col;
-    curwin->w_set_curswant = FALSE;	/* May still have been TRUE */
-    if (coladvance(col) == FAIL)	/* Mouse click beyond end of line */
-    {
-	if (inclusive != NULL)
-	    *inclusive = TRUE;
-	mouse_past_eol = TRUE;
-    }
-    else if (inclusive != NULL)
-	*inclusive = FALSE;
-
-    count = IN_BUFFER;
-    if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
-	    || curwin->w_cursor.col != old_cursor.col)
-	count |= CURSOR_MOVED;		/* Cursor has moved */
-
-# ifdef FEAT_FOLDING
-    if (mouse_char == '+')
-	count |= MOUSE_FOLD_OPEN;
-    else if (mouse_char != ' ')
-	count |= MOUSE_FOLD_CLOSE;
-# endif
-
-    return count;
-}
-#endif
-
-// Functions also used for popup windows.
-#if defined(FEAT_MOUSE) || defined(FEAT_TEXT_PROP) || defined(PROTO)
-
-/*
- * Compute the buffer line position from the screen position "rowp" / "colp" in
- * window "win".
- * "plines_cache" can be NULL (no cache) or an array with "win->w_height"
- * entries that caches the plines_win() result from a previous call.  Entry is
- * zero if not computed yet.  There must be no text or setting changes since
- * the entry is put in the cache.
- * Returns TRUE if the position is below the last line.
- */
-    int
-mouse_comp_pos(
-    win_T	*win,
-    int		*rowp,
-    int		*colp,
-    linenr_T	*lnump,
-    int		*plines_cache)
-{
-    int		col = *colp;
-    int		row = *rowp;
-    linenr_T	lnum;
-    int		retval = FALSE;
-    int		off;
-    int		count;
-
-#ifdef FEAT_RIGHTLEFT
-    if (win->w_p_rl)
-	col = win->w_width - 1 - col;
-#endif
-
-    lnum = win->w_topline;
-
-    while (row > 0)
-    {
-	int cache_idx = lnum - win->w_topline;
-
-	if (plines_cache != NULL && plines_cache[cache_idx] > 0)
-	    count = plines_cache[cache_idx];
-	else
-	{
-#ifdef FEAT_DIFF
-	    /* Don't include filler lines in "count" */
-	    if (win->w_p_diff
-# ifdef FEAT_FOLDING
-		    && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL)
-# endif
-		    )
-	    {
-		if (lnum == win->w_topline)
-		    row -= win->w_topfill;
-		else
-		    row -= diff_check_fill(win, lnum);
-		count = plines_win_nofill(win, lnum, TRUE);
-	    }
-	    else
-#endif
-		count = plines_win(win, lnum, TRUE);
-	    if (plines_cache != NULL)
-		plines_cache[cache_idx] = count;
-	}
-	if (count > row)
-	    break;	/* Position is in this buffer line. */
-#ifdef FEAT_FOLDING
-	(void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL);
-#endif
-	if (lnum == win->w_buffer->b_ml.ml_line_count)
-	{
-	    retval = TRUE;
-	    break;		/* past end of file */
-	}
-	row -= count;
-	++lnum;
-    }
-
-    if (!retval)
-    {
-	/* Compute the column without wrapping. */
-	off = win_col_off(win) - win_col_off2(win);
-	if (col < off)
-	    col = off;
-	col += row * (win->w_width - off);
-	/* add skip column (for long wrapping line) */
-	col += win->w_skipcol;
-    }
-
-    if (!win->w_p_wrap)
-	col += win->w_leftcol;
-
-    /* skip line number and fold column in front of the line */
-    col -= win_col_off(win);
-    if (col < 0)
-    {
-#ifdef FEAT_NETBEANS_INTG
-	netbeans_gutter_click(lnum);
-#endif
-	col = 0;
-    }
-
-    *colp = col;
-    *rowp = row;
-    *lnump = lnum;
-    return retval;
-}
-
-/*
- * Find the window at screen position "*rowp" and "*colp".  The positions are
- * updated to become relative to the top-left of the window.
- * When "popup" is FAIL_POPUP and the position is in a popup window then NULL
- * is returned.  When "popup" is IGNORE_POPUP then do not even check popup
- * windows.
- * Returns NULL when something is wrong.
- */
-    win_T *
-mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
-{
-    frame_T	*fp;
-    win_T	*wp;
-
-#ifdef FEAT_TEXT_PROP
-    win_T	*pwp = NULL;
-
-    if (popup != IGNORE_POPUP)
-    {
-	popup_reset_handled();
-	while ((wp = find_next_popup(TRUE)) != NULL)
-	{
-	    if (*rowp >= wp->w_winrow && *rowp < wp->w_winrow + popup_height(wp)
-		    && *colp >= wp->w_wincol
-				    && *colp < wp->w_wincol + popup_width(wp))
-		pwp = wp;
-	}
-	if (pwp != NULL)
-	{
-	    if (popup == FAIL_POPUP)
-		return NULL;
-	    *rowp -= pwp->w_winrow;
-	    *colp -= pwp->w_wincol;
-	    return pwp;
-	}
-    }
-#endif
-
-    fp = topframe;
-    *rowp -= firstwin->w_winrow;
-    for (;;)
-    {
-	if (fp->fr_layout == FR_LEAF)
-	    break;
-	if (fp->fr_layout == FR_ROW)
-	{
-	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
-	    {
-		if (*colp < fp->fr_width)
-		    break;
-		*colp -= fp->fr_width;
-	    }
-	}
-	else    /* fr_layout == FR_COL */
-	{
-	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
-	    {
-		if (*rowp < fp->fr_height)
-		    break;
-		*rowp -= fp->fr_height;
-	    }
-	}
-    }
-    /* When using a timer that closes a window the window might not actually
-     * exist. */
-    FOR_ALL_WINDOWS(wp)
-	if (wp == fp->fr_win)
-	{
-#ifdef FEAT_MENU
-	    *rowp -= wp->w_winbar_height;
-#endif
-	    return wp;
-	}
-    return NULL;
-}
-
-#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \
-	|| defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
-	|| defined(FEAT_GUI_PHOTON) || defined(FEAT_TERM_POPUP_MENU) \
-	|| defined(PROTO)
-# define NEED_VCOL2COL
-
-/*
- * Translate window coordinates to buffer position without any side effects
- */
-    int
-get_fpos_of_mouse(pos_T *mpos)
-{
-    win_T	*wp;
-    int		row = mouse_row;
-    int		col = mouse_col;
-
-    if (row < 0 || col < 0)		/* check if it makes sense */
-	return IN_UNKNOWN;
-
-    /* find the window where the row is in */
-    wp = mouse_find_win(&row, &col, FAIL_POPUP);
-    if (wp == NULL)
-	return IN_UNKNOWN;
-    /*
-     * winpos and height may change in win_enter()!
-     */
-    if (row >= wp->w_height)	/* In (or below) status line */
-	return IN_STATUS_LINE;
-    if (col >= wp->w_width)	/* In vertical separator line */
-	return IN_SEP_LINE;
-
-    if (wp != curwin)
-	return IN_UNKNOWN;
-
-    /* compute the position in the buffer line from the posn on the screen */
-    if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum, NULL))
-	return IN_STATUS_LINE; /* past bottom */
-
-    mpos->col = vcol2col(wp, mpos->lnum, col);
-
-    if (mpos->col > 0)
-	--mpos->col;
-    mpos->coladd = 0;
-    return IN_BUFFER;
-}
-#endif
-
-#if defined(NEED_VCOL2COL) || defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) \
-	|| defined(PROTO)
-/*
- * Convert a virtual (screen) column to a character column.
- * The first column is one.
- */
-    int
-vcol2col(win_T *wp, linenr_T lnum, int vcol)
-{
-    /* try to advance to the specified column */
-    int		count = 0;
-    char_u	*ptr;
-    char_u	*line;
-
-    line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
-    while (count < vcol && *ptr != NUL)
-    {
-	count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
-	MB_PTR_ADV(ptr);
-    }
-    return (int)(ptr - line);
-}
-#endif
-
-#endif /* FEAT_MOUSE */
-
 #if defined(FEAT_GUI) || defined(MSWIN) || defined(PROTO)
 /*
  * Called when focus changed.  Used for the GUI or for systems where this can
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2062,
+/**/
     2061,
 /**/
     2060,
--- a/src/vim.h
+++ b/src/vim.h
@@ -229,8 +229,10 @@
 
 // Mark unused function arguments with UNUSED, so that gcc -Wunused-parameter
 // can be used to check for mistakes.
-#ifdef HAVE_ATTRIBUTE_UNUSED
-# define UNUSED __attribute__((unused))
+#if defined(HAVE_ATTRIBUTE_UNUSED) || defined(__MINGW32__)
+# if !defined(UNUSED)
+#  define UNUSED __attribute__((unused))
+# endif
 #else
 # define UNUSED
 #endif
--- a/src/window.c
+++ b/src/window.c
@@ -4672,9 +4672,7 @@ win_enter_ext(
     if (curwin->w_width < p_wiw && !curwin->w_p_wfw)
 	win_setwidth((int)p_wiw);
 
-#ifdef FEAT_MOUSE
-    setmouse();			/* in case jumped to/from help buffer */
-#endif
+    setmouse();			// in case jumped to/from help buffer
 
     /* Change directories when the 'acd' option is set. */
     DO_AUTOCHDIR;