xref: /vim-8.2.3635/src/mouse.c (revision afe45b68)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * mouse.c: mouse handling functions
12  */
13 
14 #include "vim.h"
15 
16 /*
17  * Get class of a character for selection: same class means same word.
18  * 0: blank
19  * 1: punctuation groups
20  * 2: normal word character
21  * >2: multi-byte word character.
22  */
23     static int
24 get_mouse_class(char_u *p)
25 {
26     int		c;
27 
28     if (has_mbyte && MB_BYTE2LEN(p[0]) > 1)
29 	return mb_get_class(p);
30 
31     c = *p;
32     if (c == ' ' || c == '\t')
33 	return 0;
34 
35     if (vim_iswordc(c))
36 	return 2;
37 
38     // There are a few special cases where we want certain combinations of
39     // characters to be considered as a single word.  These are things like
40     // "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
41     // character is in its own class.
42     if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
43 	return 1;
44     return c;
45 }
46 
47 /*
48  * Move "pos" back to the start of the word it's in.
49  */
50     static void
51 find_start_of_word(pos_T *pos)
52 {
53     char_u	*line;
54     int		cclass;
55     int		col;
56 
57     line = ml_get(pos->lnum);
58     cclass = get_mouse_class(line + pos->col);
59 
60     while (pos->col > 0)
61     {
62 	col = pos->col - 1;
63 	col -= (*mb_head_off)(line, line + col);
64 	if (get_mouse_class(line + col) != cclass)
65 	    break;
66 	pos->col = col;
67     }
68 }
69 
70 /*
71  * Move "pos" forward to the end of the word it's in.
72  * When 'selection' is "exclusive", the position is just after the word.
73  */
74     static void
75 find_end_of_word(pos_T *pos)
76 {
77     char_u	*line;
78     int		cclass;
79     int		col;
80 
81     line = ml_get(pos->lnum);
82     if (*p_sel == 'e' && pos->col > 0)
83     {
84 	--pos->col;
85 	pos->col -= (*mb_head_off)(line, line + pos->col);
86     }
87     cclass = get_mouse_class(line + pos->col);
88     while (line[pos->col] != NUL)
89     {
90 	col = pos->col + (*mb_ptr2len)(line + pos->col);
91 	if (get_mouse_class(line + col) != cclass)
92 	{
93 	    if (*p_sel == 'e')
94 		pos->col = col;
95 	    break;
96 	}
97 	pos->col = col;
98     }
99 }
100 
101 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
102 	    || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
103 	    || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_PHOTON) \
104 	    || defined(FEAT_TERM_POPUP_MENU)
105 # define USE_POPUP_SETPOS
106 # define NEED_VCOL2COL
107 
108 /*
109  * Translate window coordinates to buffer position without any side effects
110  */
111     static int
112 get_fpos_of_mouse(pos_T *mpos)
113 {
114     win_T	*wp;
115     int		row = mouse_row;
116     int		col = mouse_col;
117 
118     if (row < 0 || col < 0)		// check if it makes sense
119 	return IN_UNKNOWN;
120 
121     // find the window where the row is in
122     wp = mouse_find_win(&row, &col, FAIL_POPUP);
123     if (wp == NULL)
124 	return IN_UNKNOWN;
125     // winpos and height may change in win_enter()!
126     if (row >= wp->w_height)	// In (or below) status line
127 	return IN_STATUS_LINE;
128     if (col >= wp->w_width)	// In vertical separator line
129 	return IN_SEP_LINE;
130 
131     if (wp != curwin)
132 	return IN_UNKNOWN;
133 
134     // compute the position in the buffer line from the posn on the screen
135     if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum, NULL))
136 	return IN_STATUS_LINE; // past bottom
137 
138     mpos->col = vcol2col(wp, mpos->lnum, col);
139 
140     if (mpos->col > 0)
141 	--mpos->col;
142     mpos->coladd = 0;
143     return IN_BUFFER;
144 }
145 #endif
146 
147 /*
148  * Do the appropriate action for the current mouse click in the current mode.
149  * Not used for Command-line mode.
150  *
151  * Normal and Visual Mode:
152  * event	 modi-	position      visual	   change   action
153  *		 fier	cursor			   window
154  * left press	  -	yes	    end		    yes
155  * left press	  C	yes	    end		    yes	    "^]" (2)
156  * left press	  S	yes	end (popup: extend) yes	    "*" (2)
157  * left drag	  -	yes	start if moved	    no
158  * left relse	  -	yes	start if moved	    no
159  * middle press	  -	yes	 if not active	    no	    put register
160  * middle press	  -	yes	 if active	    no	    yank and put
161  * right press	  -	yes	start or extend	    yes
162  * right press	  S	yes	no change	    yes	    "#" (2)
163  * right drag	  -	yes	extend		    no
164  * right relse	  -	yes	extend		    no
165  *
166  * Insert or Replace Mode:
167  * event	 modi-	position      visual	   change   action
168  *		 fier	cursor			   window
169  * left press	  -	yes	(cannot be active)  yes
170  * left press	  C	yes	(cannot be active)  yes	    "CTRL-O^]" (2)
171  * left press	  S	yes	(cannot be active)  yes	    "CTRL-O*" (2)
172  * left drag	  -	yes	start or extend (1) no	    CTRL-O (1)
173  * left relse	  -	yes	start or extend (1) no	    CTRL-O (1)
174  * middle press	  -	no	(cannot be active)  no	    put register
175  * right press	  -	yes	start or extend	    yes	    CTRL-O
176  * right press	  S	yes	(cannot be active)  yes	    "CTRL-O#" (2)
177  *
178  * (1) only if mouse pointer moved since press
179  * (2) only if click is in same buffer
180  *
181  * Return TRUE if start_arrow() should be called for edit mode.
182  */
183     int
184 do_mouse(
185     oparg_T	*oap,		// operator argument, can be NULL
186     int		c,		// K_LEFTMOUSE, etc
187     int		dir,		// Direction to 'put' if necessary
188     long	count,
189     int		fixindent)	// PUT_FIXINDENT if fixing indent necessary
190 {
191     static int	do_always = FALSE;	// ignore 'mouse' setting next time
192     static int	got_click = FALSE;	// got a click some time back
193 
194     int		which_button;	// MOUSE_LEFT, _MIDDLE or _RIGHT
195     int		is_click = FALSE; // If FALSE it's a drag or release event
196     int		is_drag = FALSE;  // If TRUE it's a drag event
197     int		jump_flags = 0;	// flags for jump_to_mouse()
198     pos_T	start_visual;
199     int		moved;		// Has cursor moved?
200     int		in_status_line;	// mouse in status line
201     static int	in_tab_line = FALSE; // mouse clicked in tab line
202     int		in_sep_line;	// mouse in vertical separator line
203     int		c1, c2;
204 #if defined(FEAT_FOLDING)
205     pos_T	save_cursor;
206 #endif
207     win_T	*old_curwin = curwin;
208     static pos_T orig_cursor;
209     colnr_T	leftcol, rightcol;
210     pos_T	end_visual;
211     int		diff;
212     int		old_active = VIsual_active;
213     int		old_mode = VIsual_mode;
214     int		regname;
215 
216 #if defined(FEAT_FOLDING)
217     save_cursor = curwin->w_cursor;
218 #endif
219 
220     // When GUI is active, always recognize mouse events, otherwise:
221     // - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
222     // - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
223     // - For command line and insert mode 'mouse' is checked before calling
224     //	 do_mouse().
225     if (do_always)
226 	do_always = FALSE;
227     else
228 #ifdef FEAT_GUI
229 	if (!gui.in_use)
230 #endif
231 	{
232 	    if (VIsual_active)
233 	    {
234 		if (!mouse_has(MOUSE_VISUAL))
235 		    return FALSE;
236 	    }
237 	    else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
238 		return FALSE;
239 	}
240 
241     for (;;)
242     {
243 	which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
244 	if (is_drag)
245 	{
246 	    // If the next character is the same mouse event then use that
247 	    // one. Speeds up dragging the status line.
248 	    if (vpeekc() != NUL)
249 	    {
250 		int nc;
251 		int save_mouse_row = mouse_row;
252 		int save_mouse_col = mouse_col;
253 
254 		// Need to get the character, peeking doesn't get the actual
255 		// one.
256 		nc = safe_vgetc();
257 		if (c == nc)
258 		    continue;
259 		vungetc(nc);
260 		mouse_row = save_mouse_row;
261 		mouse_col = save_mouse_col;
262 	    }
263 	}
264 	break;
265     }
266 
267     if (c == K_MOUSEMOVE)
268     {
269 	// Mouse moved without a button pressed.
270 #ifdef FEAT_BEVAL_TERM
271 	ui_may_remove_balloon();
272 	if (p_bevalterm)
273 	{
274 	    profile_setlimit(p_bdlay, &bevalexpr_due);
275 	    bevalexpr_due_set = TRUE;
276 	}
277 #endif
278 #ifdef FEAT_TEXT_PROP
279 	popup_handle_mouse_moved();
280 #endif
281 	return FALSE;
282     }
283 
284 #ifdef FEAT_MOUSESHAPE
285     // May have stopped dragging the status or separator line.  The pointer is
286     // most likely still on the status or separator line.
287     if (!is_drag && drag_status_line)
288     {
289 	drag_status_line = FALSE;
290 	update_mouseshape(SHAPE_IDX_STATUS);
291     }
292     if (!is_drag && drag_sep_line)
293     {
294 	drag_sep_line = FALSE;
295 	update_mouseshape(SHAPE_IDX_VSEP);
296     }
297 #endif
298 
299     // Ignore drag and release events if we didn't get a click.
300     if (is_click)
301 	got_click = TRUE;
302     else
303     {
304 	if (!got_click)			// didn't get click, ignore
305 	    return FALSE;
306 	if (!is_drag)			// release, reset got_click
307 	{
308 	    got_click = FALSE;
309 	    if (in_tab_line)
310 	    {
311 		in_tab_line = FALSE;
312 		return FALSE;
313 	    }
314 	}
315     }
316 
317     // CTRL right mouse button does CTRL-T
318     if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
319     {
320 	if (State & INSERT)
321 	    stuffcharReadbuff(Ctrl_O);
322 	if (count > 1)
323 	    stuffnumReadbuff(count);
324 	stuffcharReadbuff(Ctrl_T);
325 	got_click = FALSE;		// ignore drag&release now
326 	return FALSE;
327     }
328 
329     // CTRL only works with left mouse button
330     if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
331 	return FALSE;
332 
333     // When a modifier is down, ignore drag and release events, as well as
334     // multiple clicks and the middle mouse button.
335     // Accept shift-leftmouse drags when 'mousemodel' is "popup.*".
336     if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT
337 							     | MOD_MASK_META))
338 	    && (!is_click
339 		|| (mod_mask & MOD_MASK_MULTI_CLICK)
340 		|| which_button == MOUSE_MIDDLE)
341 	    && !((mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))
342 		&& mouse_model_popup()
343 		&& which_button == MOUSE_LEFT)
344 	    && !((mod_mask & MOD_MASK_ALT)
345 		&& !mouse_model_popup()
346 		&& which_button == MOUSE_RIGHT)
347 	    )
348 	return FALSE;
349 
350     // If the button press was used as the movement command for an operator
351     // (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
352     // drag/release events.
353     if (!is_click && which_button == MOUSE_MIDDLE)
354 	return FALSE;
355 
356     if (oap != NULL)
357 	regname = oap->regname;
358     else
359 	regname = 0;
360 
361     // Middle mouse button does a 'put' of the selected text
362     if (which_button == MOUSE_MIDDLE)
363     {
364 	if (State == NORMAL)
365 	{
366 	    // If an operator was pending, we don't know what the user wanted
367 	    // to do. Go back to normal mode: Clear the operator and beep().
368 	    if (oap != NULL && oap->op_type != OP_NOP)
369 	    {
370 		clearopbeep(oap);
371 		return FALSE;
372 	    }
373 
374 	    // If visual was active, yank the highlighted text and put it
375 	    // before the mouse pointer position.
376 	    // In Select mode replace the highlighted text with the clipboard.
377 	    if (VIsual_active)
378 	    {
379 		if (VIsual_select)
380 		{
381 		    stuffcharReadbuff(Ctrl_G);
382 		    stuffReadbuff((char_u *)"\"+p");
383 		}
384 		else
385 		{
386 		    stuffcharReadbuff('y');
387 		    stuffcharReadbuff(K_MIDDLEMOUSE);
388 		}
389 		do_always = TRUE;	// ignore 'mouse' setting next time
390 		return FALSE;
391 	    }
392 	    // The rest is below jump_to_mouse()
393 	}
394 
395 	else if ((State & INSERT) == 0)
396 	    return FALSE;
397 
398 	// Middle click in insert mode doesn't move the mouse, just insert the
399 	// contents of a register.  '.' register is special, can't insert that
400 	// with do_put().
401 	// Also paste at the cursor if the current mode isn't in 'mouse' (only
402 	// happens for the GUI).
403 	if ((State & INSERT) || !mouse_has(MOUSE_NORMAL))
404 	{
405 	    if (regname == '.')
406 		insert_reg(regname, TRUE);
407 	    else
408 	    {
409 #ifdef FEAT_CLIPBOARD
410 		if (clip_star.available && regname == 0)
411 		    regname = '*';
412 #endif
413 		if ((State & REPLACE_FLAG) && !yank_register_mline(regname))
414 		    insert_reg(regname, TRUE);
415 		else
416 		{
417 		    do_put(regname, BACKWARD, 1L, fixindent | PUT_CURSEND);
418 
419 		    // Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r
420 		    AppendCharToRedobuff(Ctrl_R);
421 		    AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O);
422 		    AppendCharToRedobuff(regname == 0 ? '"' : regname);
423 		}
424 	    }
425 	    return FALSE;
426 	}
427     }
428 
429     // When dragging or button-up stay in the same window.
430     if (!is_click)
431 	jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
432 
433     start_visual.lnum = 0;
434 
435     // Check for clicking in the tab page line.
436     if (mouse_row == 0 && firstwin->w_winrow > 0)
437     {
438 	if (is_drag)
439 	{
440 	    if (in_tab_line)
441 	    {
442 		c1 = TabPageIdxs[mouse_col];
443 		tabpage_move(c1 <= 0 ? 9999 : c1 < tabpage_index(curtab)
444 								? c1 - 1 : c1);
445 	    }
446 	    return FALSE;
447 	}
448 
449 	// click in a tab selects that tab page
450 	if (is_click
451 # ifdef FEAT_CMDWIN
452 		&& cmdwin_type == 0
453 # endif
454 		&& mouse_col < Columns)
455 	{
456 	    in_tab_line = TRUE;
457 	    c1 = TabPageIdxs[mouse_col];
458 	    if (c1 >= 0)
459 	    {
460 		if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
461 		{
462 		    // double click opens new page
463 		    end_visual_mode();
464 		    tabpage_new();
465 		    tabpage_move(c1 == 0 ? 9999 : c1 - 1);
466 		}
467 		else
468 		{
469 		    // Go to specified tab page, or next one if not clicking
470 		    // on a label.
471 		    goto_tabpage(c1);
472 
473 		    // It's like clicking on the status line of a window.
474 		    if (curwin != old_curwin)
475 			end_visual_mode();
476 		}
477 	    }
478 	    else
479 	    {
480 		tabpage_T	*tp;
481 
482 		// Close the current or specified tab page.
483 		if (c1 == -999)
484 		    tp = curtab;
485 		else
486 		    tp = find_tabpage(-c1);
487 		if (tp == curtab)
488 		{
489 		    if (first_tabpage->tp_next != NULL)
490 			tabpage_close(FALSE);
491 		}
492 		else if (tp != NULL)
493 		    tabpage_close_other(tp, FALSE);
494 	    }
495 	}
496 	return TRUE;
497     }
498     else if (is_drag && in_tab_line)
499     {
500 	c1 = TabPageIdxs[mouse_col];
501 	tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
502 	return FALSE;
503     }
504 
505     // When 'mousemodel' is "popup" or "popup_setpos", translate mouse events:
506     // right button up   -> pop-up menu
507     // shift-left button -> right button
508     // alt-left button   -> alt-right button
509     if (mouse_model_popup())
510     {
511 	if (which_button == MOUSE_RIGHT
512 			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
513 	{
514 #ifdef USE_POPUP_SETPOS
515 # ifdef FEAT_GUI
516 	    if (gui.in_use)
517 	    {
518 #  if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
519 			  || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
520 		if (!is_click)
521 		    // Ignore right button release events, only shows the popup
522 		    // menu on the button down event.
523 		    return FALSE;
524 #  endif
525 #  if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN)
526 		if (is_click || is_drag)
527 		    // Ignore right button down and drag mouse events.  Windows
528 		    // only shows the popup menu on the button up event.
529 		    return FALSE;
530 #  endif
531 	    }
532 # endif
533 # if defined(FEAT_GUI) && defined(FEAT_TERM_POPUP_MENU)
534 	    else
535 # endif
536 # if defined(FEAT_TERM_POPUP_MENU)
537 	    if (!is_click)
538 		// Ignore right button release events, only shows the popup
539 		// menu on the button down event.
540 		return FALSE;
541 #endif
542 
543 	    jump_flags = 0;
544 	    if (STRCMP(p_mousem, "popup_setpos") == 0)
545 	    {
546 		// First set the cursor position before showing the popup
547 		// menu.
548 		if (VIsual_active)
549 		{
550 		    pos_T    m_pos;
551 
552 		    // set MOUSE_MAY_STOP_VIS if we are outside the
553 		    // selection or the current window (might have false
554 		    // negative here)
555 		    if (mouse_row < curwin->w_winrow
556 			 || mouse_row
557 				  > (curwin->w_winrow + curwin->w_height))
558 			jump_flags = MOUSE_MAY_STOP_VIS;
559 		    else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER)
560 			jump_flags = MOUSE_MAY_STOP_VIS;
561 		    else
562 		    {
563 			if ((LT_POS(curwin->w_cursor, VIsual)
564 				    && (LT_POS(m_pos, curwin->w_cursor)
565 					|| LT_POS(VIsual, m_pos)))
566 				|| (LT_POS(VIsual, curwin->w_cursor)
567 				    && (LT_POS(m_pos, VIsual)
568 				      || LT_POS(curwin->w_cursor, m_pos))))
569 			{
570 			    jump_flags = MOUSE_MAY_STOP_VIS;
571 			}
572 			else if (VIsual_mode == Ctrl_V)
573 			{
574 			    getvcols(curwin, &curwin->w_cursor, &VIsual,
575 						     &leftcol, &rightcol);
576 			    getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
577 			    if (m_pos.col < leftcol || m_pos.col > rightcol)
578 				jump_flags = MOUSE_MAY_STOP_VIS;
579 			}
580 		    }
581 		}
582 		else
583 		    jump_flags = MOUSE_MAY_STOP_VIS;
584 	    }
585 	    if (jump_flags)
586 	    {
587 		jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
588 		update_curbuf(VIsual_active ? INVERTED : VALID);
589 		setcursor();
590 		out_flush();    // Update before showing popup menu
591 	    }
592 # ifdef FEAT_MENU
593 	    show_popupmenu();
594 	    got_click = FALSE;	// ignore release events
595 # endif
596 	    return (jump_flags & CURSOR_MOVED) != 0;
597 #else
598 	    return FALSE;
599 #endif
600 	}
601 	if (which_button == MOUSE_LEFT
602 				&& (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT)))
603 	{
604 	    which_button = MOUSE_RIGHT;
605 	    mod_mask &= ~MOD_MASK_SHIFT;
606 	}
607     }
608 
609     if ((State & (NORMAL | INSERT))
610 			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
611     {
612 	if (which_button == MOUSE_LEFT)
613 	{
614 	    if (is_click)
615 	    {
616 		// stop Visual mode for a left click in a window, but not when
617 		// on a status line
618 		if (VIsual_active)
619 		    jump_flags |= MOUSE_MAY_STOP_VIS;
620 	    }
621 	    else if (mouse_has(MOUSE_VISUAL))
622 		jump_flags |= MOUSE_MAY_VIS;
623 	}
624 	else if (which_button == MOUSE_RIGHT)
625 	{
626 	    if (is_click && VIsual_active)
627 	    {
628 		// Remember the start and end of visual before moving the
629 		// cursor.
630 		if (LT_POS(curwin->w_cursor, VIsual))
631 		{
632 		    start_visual = curwin->w_cursor;
633 		    end_visual = VIsual;
634 		}
635 		else
636 		{
637 		    start_visual = VIsual;
638 		    end_visual = curwin->w_cursor;
639 		}
640 	    }
641 	    jump_flags |= MOUSE_FOCUS;
642 	    if (mouse_has(MOUSE_VISUAL))
643 		jump_flags |= MOUSE_MAY_VIS;
644 	}
645     }
646 
647     // If an operator is pending, ignore all drags and releases until the
648     // next mouse click.
649     if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
650     {
651 	got_click = FALSE;
652 	oap->motion_type = MCHAR;
653     }
654 
655     // When releasing the button let jump_to_mouse() know.
656     if (!is_click && !is_drag)
657 	jump_flags |= MOUSE_RELEASED;
658 
659     // JUMP!
660     jump_flags = jump_to_mouse(jump_flags,
661 			oap == NULL ? NULL : &(oap->inclusive), which_button);
662 
663 #ifdef FEAT_MENU
664     // A click in the window toolbar has no side effects.
665     if (jump_flags & MOUSE_WINBAR)
666 	return FALSE;
667 #endif
668     moved = (jump_flags & CURSOR_MOVED);
669     in_status_line = (jump_flags & IN_STATUS_LINE);
670     in_sep_line = (jump_flags & IN_SEP_LINE);
671 
672 #ifdef FEAT_NETBEANS_INTG
673     if (isNetbeansBuffer(curbuf)
674 			    && !(jump_flags & (IN_STATUS_LINE | IN_SEP_LINE)))
675     {
676 	int key = KEY2TERMCAP1(c);
677 
678 	if (key == (int)KE_LEFTRELEASE || key == (int)KE_MIDDLERELEASE
679 					       || key == (int)KE_RIGHTRELEASE)
680 	    netbeans_button_release(which_button);
681     }
682 #endif
683 
684     // When jumping to another window, clear a pending operator.  That's a bit
685     // friendlier than beeping and not jumping to that window.
686     if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP)
687 	clearop(oap);
688 
689 #ifdef FEAT_FOLDING
690     if (mod_mask == 0
691 	    && !is_drag
692 	    && (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN))
693 	    && which_button == MOUSE_LEFT)
694     {
695 	// open or close a fold at this line
696 	if (jump_flags & MOUSE_FOLD_OPEN)
697 	    openFold(curwin->w_cursor.lnum, 1L);
698 	else
699 	    closeFold(curwin->w_cursor.lnum, 1L);
700 	// don't move the cursor if still in the same window
701 	if (curwin == old_curwin)
702 	    curwin->w_cursor = save_cursor;
703     }
704 #endif
705 
706 #if defined(FEAT_CLIPBOARD) && defined(FEAT_CMDWIN)
707     if ((jump_flags & IN_OTHER_WIN) && !VIsual_active && clip_star.available)
708     {
709 	clip_modeless(which_button, is_click, is_drag);
710 	return FALSE;
711     }
712 #endif
713 
714     // Set global flag that we are extending the Visual area with mouse
715     // dragging; temporarily minimize 'scrolloff'.
716     if (VIsual_active && is_drag && get_scrolloff_value())
717     {
718 	// In the very first line, allow scrolling one line
719 	if (mouse_row == 0)
720 	    mouse_dragging = 2;
721 	else
722 	    mouse_dragging = 1;
723     }
724 
725     // When dragging the mouse above the window, scroll down.
726     if (is_drag && mouse_row < 0 && !in_status_line)
727     {
728 	scroll_redraw(FALSE, 1L);
729 	mouse_row = 0;
730     }
731 
732     if (start_visual.lnum)		// right click in visual mode
733     {
734        // When ALT is pressed make Visual mode blockwise.
735        if (mod_mask & MOD_MASK_ALT)
736 	   VIsual_mode = Ctrl_V;
737 
738 	// In Visual-block mode, divide the area in four, pick up the corner
739 	// that is in the quarter that the cursor is in.
740 	if (VIsual_mode == Ctrl_V)
741 	{
742 	    getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol);
743 	    if (curwin->w_curswant > (leftcol + rightcol) / 2)
744 		end_visual.col = leftcol;
745 	    else
746 		end_visual.col = rightcol;
747 	    if (curwin->w_cursor.lnum >=
748 				    (start_visual.lnum + end_visual.lnum) / 2)
749 		end_visual.lnum = start_visual.lnum;
750 
751 	    // move VIsual to the right column
752 	    start_visual = curwin->w_cursor;	    // save the cursor pos
753 	    curwin->w_cursor = end_visual;
754 	    coladvance(end_visual.col);
755 	    VIsual = curwin->w_cursor;
756 	    curwin->w_cursor = start_visual;	    // restore the cursor
757 	}
758 	else
759 	{
760 	    // If the click is before the start of visual, change the start.
761 	    // If the click is after the end of visual, change the end.  If
762 	    // the click is inside the visual, change the closest side.
763 	    if (LT_POS(curwin->w_cursor, start_visual))
764 		VIsual = end_visual;
765 	    else if (LT_POS(end_visual, curwin->w_cursor))
766 		VIsual = start_visual;
767 	    else
768 	    {
769 		// In the same line, compare column number
770 		if (end_visual.lnum == start_visual.lnum)
771 		{
772 		    if (curwin->w_cursor.col - start_visual.col >
773 				    end_visual.col - curwin->w_cursor.col)
774 			VIsual = start_visual;
775 		    else
776 			VIsual = end_visual;
777 		}
778 
779 		// In different lines, compare line number
780 		else
781 		{
782 		    diff = (curwin->w_cursor.lnum - start_visual.lnum) -
783 				(end_visual.lnum - curwin->w_cursor.lnum);
784 
785 		    if (diff > 0)		// closest to end
786 			VIsual = start_visual;
787 		    else if (diff < 0)	// closest to start
788 			VIsual = end_visual;
789 		    else			// in the middle line
790 		    {
791 			if (curwin->w_cursor.col <
792 					(start_visual.col + end_visual.col) / 2)
793 			    VIsual = end_visual;
794 			else
795 			    VIsual = start_visual;
796 		    }
797 		}
798 	    }
799 	}
800     }
801     // If Visual mode started in insert mode, execute "CTRL-O"
802     else if ((State & INSERT) && VIsual_active)
803 	stuffcharReadbuff(Ctrl_O);
804 
805     // Middle mouse click: Put text before cursor.
806     if (which_button == MOUSE_MIDDLE)
807     {
808 #ifdef FEAT_CLIPBOARD
809 	if (clip_star.available && regname == 0)
810 	    regname = '*';
811 #endif
812 	if (yank_register_mline(regname))
813 	{
814 	    if (mouse_past_bottom)
815 		dir = FORWARD;
816 	}
817 	else if (mouse_past_eol)
818 	    dir = FORWARD;
819 
820 	if (fixindent)
821 	{
822 	    c1 = (dir == BACKWARD) ? '[' : ']';
823 	    c2 = 'p';
824 	}
825 	else
826 	{
827 	    c1 = (dir == FORWARD) ? 'p' : 'P';
828 	    c2 = NUL;
829 	}
830 	prep_redo(regname, count, NUL, c1, NUL, c2, NUL);
831 
832 	// Remember where the paste started, so in edit() Insstart can be set
833 	// to this position
834 	if (restart_edit != 0)
835 	    where_paste_started = curwin->w_cursor;
836 	do_put(regname, dir, count, fixindent | PUT_CURSEND);
837     }
838 
839 #if defined(FEAT_QUICKFIX)
840     // Ctrl-Mouse click or double click in a quickfix window jumps to the
841     // error under the mouse pointer.
842     else if (((mod_mask & MOD_MASK_CTRL)
843 		|| (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
844 	    && bt_quickfix(curbuf))
845     {
846 	if (curwin->w_llist_ref == NULL)	// quickfix window
847 	    do_cmdline_cmd((char_u *)".cc");
848 	else					// location list window
849 	    do_cmdline_cmd((char_u *)".ll");
850 	got_click = FALSE;		// ignore drag&release now
851     }
852 #endif
853 
854     // Ctrl-Mouse click (or double click in a help window) jumps to the tag
855     // under the mouse pointer.
856     else if ((mod_mask & MOD_MASK_CTRL) || (curbuf->b_help
857 		     && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK))
858     {
859 	if (State & INSERT)
860 	    stuffcharReadbuff(Ctrl_O);
861 	stuffcharReadbuff(Ctrl_RSB);
862 	got_click = FALSE;		// ignore drag&release now
863     }
864 
865     // Shift-Mouse click searches for the next occurrence of the word under
866     // the mouse pointer
867     else if ((mod_mask & MOD_MASK_SHIFT))
868     {
869 	if ((State & INSERT) || (VIsual_active && VIsual_select))
870 	    stuffcharReadbuff(Ctrl_O);
871 	if (which_button == MOUSE_LEFT)
872 	    stuffcharReadbuff('*');
873 	else	// MOUSE_RIGHT
874 	    stuffcharReadbuff('#');
875     }
876 
877     // Handle double clicks, unless on status line
878     else if (in_status_line)
879     {
880 #ifdef FEAT_MOUSESHAPE
881 	if ((is_drag || is_click) && !drag_status_line)
882 	{
883 	    drag_status_line = TRUE;
884 	    update_mouseshape(-1);
885 	}
886 #endif
887     }
888     else if (in_sep_line)
889     {
890 #ifdef FEAT_MOUSESHAPE
891 	if ((is_drag || is_click) && !drag_sep_line)
892 	{
893 	    drag_sep_line = TRUE;
894 	    update_mouseshape(-1);
895 	}
896 #endif
897     }
898     else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))
899 	     && mouse_has(MOUSE_VISUAL))
900     {
901 	if (is_click || !VIsual_active)
902 	{
903 	    if (VIsual_active)
904 		orig_cursor = VIsual;
905 	    else
906 	    {
907 		check_visual_highlight();
908 		VIsual = curwin->w_cursor;
909 		orig_cursor = VIsual;
910 		VIsual_active = TRUE;
911 		VIsual_reselect = TRUE;
912 		// start Select mode if 'selectmode' contains "mouse"
913 		may_start_select('o');
914 		setmouse();
915 	    }
916 	    if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
917 	    {
918 		// Double click with ALT pressed makes it blockwise.
919 		if (mod_mask & MOD_MASK_ALT)
920 		    VIsual_mode = Ctrl_V;
921 		else
922 		    VIsual_mode = 'v';
923 	    }
924 	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK)
925 		VIsual_mode = 'V';
926 	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK)
927 		VIsual_mode = Ctrl_V;
928 #ifdef FEAT_CLIPBOARD
929 	    // Make sure the clipboard gets updated.  Needed because start and
930 	    // end may still be the same, and the selection needs to be owned
931 	    clip_star.vmode = NUL;
932 #endif
933 	}
934 	// A double click selects a word or a block.
935 	if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
936 	{
937 	    pos_T	*pos = NULL;
938 	    int		gc;
939 
940 	    if (is_click)
941 	    {
942 		// If the character under the cursor (skipping white space) is
943 		// not a word character, try finding a match and select a (),
944 		// {}, [], #if/#endif, etc. block.
945 		end_visual = curwin->w_cursor;
946 		while (gc = gchar_pos(&end_visual), VIM_ISWHITE(gc))
947 		    inc(&end_visual);
948 		if (oap != NULL)
949 		    oap->motion_type = MCHAR;
950 		if (oap != NULL
951 			&& VIsual_mode == 'v'
952 			&& !vim_iswordc(gchar_pos(&end_visual))
953 			&& EQUAL_POS(curwin->w_cursor, VIsual)
954 			&& (pos = findmatch(oap, NUL)) != NULL)
955 		{
956 		    curwin->w_cursor = *pos;
957 		    if (oap->motion_type == MLINE)
958 			VIsual_mode = 'V';
959 		    else if (*p_sel == 'e')
960 		    {
961 			if (LT_POS(curwin->w_cursor, VIsual))
962 			    ++VIsual.col;
963 			else
964 			    ++curwin->w_cursor.col;
965 		    }
966 		}
967 	    }
968 
969 	    if (pos == NULL && (is_click || is_drag))
970 	    {
971 		// When not found a match or when dragging: extend to include
972 		// a word.
973 		if (LT_POS(curwin->w_cursor, orig_cursor))
974 		{
975 		    find_start_of_word(&curwin->w_cursor);
976 		    find_end_of_word(&VIsual);
977 		}
978 		else
979 		{
980 		    find_start_of_word(&VIsual);
981 		    if (*p_sel == 'e' && *ml_get_cursor() != NUL)
982 			curwin->w_cursor.col +=
983 					 (*mb_ptr2len)(ml_get_cursor());
984 		    find_end_of_word(&curwin->w_cursor);
985 		}
986 	    }
987 	    curwin->w_set_curswant = TRUE;
988 	}
989 	if (is_click)
990 	    redraw_curbuf_later(INVERTED);	// update the inversion
991     }
992     else if (VIsual_active && !old_active)
993     {
994 	if (mod_mask & MOD_MASK_ALT)
995 	    VIsual_mode = Ctrl_V;
996 	else
997 	    VIsual_mode = 'v';
998     }
999 
1000     // If Visual mode changed show it later.
1001     if ((!VIsual_active && old_active && mode_displayed)
1002 	    || (VIsual_active && p_smd && msg_silent == 0
1003 				 && (!old_active || VIsual_mode != old_mode)))
1004 	redraw_cmdline = TRUE;
1005 
1006     return moved;
1007 }
1008 
1009     void
1010 ins_mouse(int c)
1011 {
1012     pos_T	tpos;
1013     win_T	*old_curwin = curwin;
1014 
1015 # ifdef FEAT_GUI
1016     // When GUI is active, also move/paste when 'mouse' is empty
1017     if (!gui.in_use)
1018 # endif
1019 	if (!mouse_has(MOUSE_INSERT))
1020 	    return;
1021 
1022     undisplay_dollar();
1023     tpos = curwin->w_cursor;
1024     if (do_mouse(NULL, c, BACKWARD, 1L, 0))
1025     {
1026 	win_T	*new_curwin = curwin;
1027 
1028 	if (curwin != old_curwin && win_valid(old_curwin))
1029 	{
1030 	    // Mouse took us to another window.  We need to go back to the
1031 	    // previous one to stop insert there properly.
1032 	    curwin = old_curwin;
1033 	    curbuf = curwin->w_buffer;
1034 #ifdef FEAT_JOB_CHANNEL
1035 	    if (bt_prompt(curbuf))
1036 		// Restart Insert mode when re-entering the prompt buffer.
1037 		curbuf->b_prompt_insert = 'A';
1038 #endif
1039 	}
1040 	start_arrow(curwin == old_curwin ? &tpos : NULL);
1041 	if (curwin != new_curwin && win_valid(new_curwin))
1042 	{
1043 	    curwin = new_curwin;
1044 	    curbuf = curwin->w_buffer;
1045 	}
1046 # ifdef FEAT_CINDENT
1047 	set_can_cindent(TRUE);
1048 # endif
1049     }
1050 
1051     // redraw status lines (in case another window became active)
1052     redraw_statuslines();
1053 }
1054 
1055     void
1056 ins_mousescroll(int dir)
1057 {
1058     pos_T	tpos;
1059     win_T	*old_curwin = curwin, *wp;
1060     int		did_scroll = FALSE;
1061 
1062     tpos = curwin->w_cursor;
1063 
1064     if (mouse_row >= 0 && mouse_col >= 0)
1065     {
1066 	int row, col;
1067 
1068 	row = mouse_row;
1069 	col = mouse_col;
1070 
1071 	// find the window at the pointer coordinates
1072 	wp = mouse_find_win(&row, &col, FIND_POPUP);
1073 	if (wp == NULL)
1074 	    return;
1075 	curwin = wp;
1076 	curbuf = curwin->w_buffer;
1077     }
1078     if (curwin == old_curwin)
1079 	undisplay_dollar();
1080 
1081     // Don't scroll the window in which completion is being done.
1082     if (!pum_visible() || curwin != old_curwin)
1083     {
1084 	if (dir == MSCR_DOWN || dir == MSCR_UP)
1085 	{
1086 	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
1087 		scroll_redraw(dir,
1088 			(long)(curwin->w_botline - curwin->w_topline));
1089 	    else
1090 		scroll_redraw(dir, 3L);
1091 # ifdef FEAT_TEXT_PROP
1092 	if (WIN_IS_POPUP(curwin))
1093 	    popup_set_firstline(curwin);
1094 # endif
1095 	}
1096 #ifdef FEAT_GUI
1097 	else
1098 	{
1099 	    int val, step = 6;
1100 
1101 	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
1102 		step = curwin->w_width;
1103 	    val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step);
1104 	    if (val < 0)
1105 		val = 0;
1106 	    gui_do_horiz_scroll(val, TRUE);
1107 	}
1108 #endif
1109 	did_scroll = TRUE;
1110     }
1111 
1112     curwin->w_redr_status = TRUE;
1113 
1114     curwin = old_curwin;
1115     curbuf = curwin->w_buffer;
1116 
1117     // The popup menu may overlay the window, need to redraw it.
1118     // TODO: Would be more efficient to only redraw the windows that are
1119     // overlapped by the popup menu.
1120     if (pum_visible() && did_scroll)
1121     {
1122 	redraw_all_later(NOT_VALID);
1123 	ins_compl_show_pum();
1124     }
1125 
1126     if (!EQUAL_POS(curwin->w_cursor, tpos))
1127     {
1128 	start_arrow(&tpos);
1129 # ifdef FEAT_CINDENT
1130 	set_can_cindent(TRUE);
1131 # endif
1132     }
1133 }
1134 
1135 /*
1136  * Return TRUE if "c" is a mouse key.
1137  */
1138     int
1139 is_mouse_key(int c)
1140 {
1141     return c == K_LEFTMOUSE
1142 	|| c == K_LEFTMOUSE_NM
1143 	|| c == K_LEFTDRAG
1144 	|| c == K_LEFTRELEASE
1145 	|| c == K_LEFTRELEASE_NM
1146 	|| c == K_MOUSEMOVE
1147 	|| c == K_MIDDLEMOUSE
1148 	|| c == K_MIDDLEDRAG
1149 	|| c == K_MIDDLERELEASE
1150 	|| c == K_RIGHTMOUSE
1151 	|| c == K_RIGHTDRAG
1152 	|| c == K_RIGHTRELEASE
1153 	|| c == K_MOUSEDOWN
1154 	|| c == K_MOUSEUP
1155 	|| c == K_MOUSELEFT
1156 	|| c == K_MOUSERIGHT
1157 	|| c == K_X1MOUSE
1158 	|| c == K_X1DRAG
1159 	|| c == K_X1RELEASE
1160 	|| c == K_X2MOUSE
1161 	|| c == K_X2DRAG
1162 	|| c == K_X2RELEASE;
1163 }
1164 
1165 static struct mousetable
1166 {
1167     int	    pseudo_code;	// Code for pseudo mouse event
1168     int	    button;		// Which mouse button is it?
1169     int	    is_click;		// Is it a mouse button click event?
1170     int	    is_drag;		// Is it a mouse drag event?
1171 } mouse_table[] =
1172 {
1173     {(int)KE_LEFTMOUSE,		MOUSE_LEFT,	TRUE,	FALSE},
1174 #ifdef FEAT_GUI
1175     {(int)KE_LEFTMOUSE_NM,	MOUSE_LEFT,	TRUE,	FALSE},
1176 #endif
1177     {(int)KE_LEFTDRAG,		MOUSE_LEFT,	FALSE,	TRUE},
1178     {(int)KE_LEFTRELEASE,	MOUSE_LEFT,	FALSE,	FALSE},
1179 #ifdef FEAT_GUI
1180     {(int)KE_LEFTRELEASE_NM,	MOUSE_LEFT,	FALSE,	FALSE},
1181 #endif
1182     {(int)KE_MIDDLEMOUSE,	MOUSE_MIDDLE,	TRUE,	FALSE},
1183     {(int)KE_MIDDLEDRAG,	MOUSE_MIDDLE,	FALSE,	TRUE},
1184     {(int)KE_MIDDLERELEASE,	MOUSE_MIDDLE,	FALSE,	FALSE},
1185     {(int)KE_RIGHTMOUSE,	MOUSE_RIGHT,	TRUE,	FALSE},
1186     {(int)KE_RIGHTDRAG,		MOUSE_RIGHT,	FALSE,	TRUE},
1187     {(int)KE_RIGHTRELEASE,	MOUSE_RIGHT,	FALSE,	FALSE},
1188     {(int)KE_X1MOUSE,		MOUSE_X1,	TRUE,	FALSE},
1189     {(int)KE_X1DRAG,		MOUSE_X1,	FALSE,	TRUE},
1190     {(int)KE_X1RELEASE,		MOUSE_X1,	FALSE,	FALSE},
1191     {(int)KE_X2MOUSE,		MOUSE_X2,	TRUE,	FALSE},
1192     {(int)KE_X2DRAG,		MOUSE_X2,	FALSE,	TRUE},
1193     {(int)KE_X2RELEASE,		MOUSE_X2,	FALSE,	FALSE},
1194     // DRAG without CLICK
1195     {(int)KE_MOUSEMOVE,		MOUSE_RELEASE,	FALSE,	TRUE},
1196     // RELEASE without CLICK
1197     {(int)KE_IGNORE,		MOUSE_RELEASE,	FALSE,	FALSE},
1198     {0,				0,		0,	0},
1199 };
1200 
1201 /*
1202  * Look up the given mouse code to return the relevant information in the other
1203  * arguments.  Return which button is down or was released.
1204  */
1205     int
1206 get_mouse_button(int code, int *is_click, int *is_drag)
1207 {
1208     int	    i;
1209 
1210     for (i = 0; mouse_table[i].pseudo_code; i++)
1211 	if (code == mouse_table[i].pseudo_code)
1212 	{
1213 	    *is_click = mouse_table[i].is_click;
1214 	    *is_drag = mouse_table[i].is_drag;
1215 	    return mouse_table[i].button;
1216 	}
1217     return 0;	    // Shouldn't get here
1218 }
1219 
1220 /*
1221  * Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
1222  * the given information about which mouse button is down, and whether the
1223  * mouse was clicked, dragged or released.
1224  */
1225     int
1226 get_pseudo_mouse_code(
1227     int	    button,	// eg MOUSE_LEFT
1228     int	    is_click,
1229     int	    is_drag)
1230 {
1231     int	    i;
1232 
1233     for (i = 0; mouse_table[i].pseudo_code; i++)
1234 	if (button == mouse_table[i].button
1235 	    && is_click == mouse_table[i].is_click
1236 	    && is_drag == mouse_table[i].is_drag)
1237 	{
1238 #ifdef FEAT_GUI
1239 	    // Trick: a non mappable left click and release has mouse_col -1
1240 	    // or added MOUSE_COLOFF.  Used for 'mousefocus' in
1241 	    // gui_mouse_moved()
1242 	    if (mouse_col < 0 || mouse_col > MOUSE_COLOFF)
1243 	    {
1244 		if (mouse_col < 0)
1245 		    mouse_col = 0;
1246 		else
1247 		    mouse_col -= MOUSE_COLOFF;
1248 		if (mouse_table[i].pseudo_code == (int)KE_LEFTMOUSE)
1249 		    return (int)KE_LEFTMOUSE_NM;
1250 		if (mouse_table[i].pseudo_code == (int)KE_LEFTRELEASE)
1251 		    return (int)KE_LEFTRELEASE_NM;
1252 	    }
1253 #endif
1254 	    return mouse_table[i].pseudo_code;
1255 	}
1256     return (int)KE_IGNORE;	    // not recognized, ignore it
1257 }
1258 
1259 # define HMT_NORMAL	1
1260 # define HMT_NETTERM	2
1261 # define HMT_DEC	4
1262 # define HMT_JSBTERM	8
1263 # define HMT_PTERM	16
1264 # define HMT_URXVT	32
1265 # define HMT_GPM	64
1266 # define HMT_SGR	128
1267 # define HMT_SGR_REL	256
1268 static int has_mouse_termcode = 0;
1269 
1270     void
1271 set_mouse_termcode(
1272     int		n,	// KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE
1273     char_u	*s)
1274 {
1275     char_u	name[2];
1276 
1277     name[0] = n;
1278     name[1] = KE_FILLER;
1279     add_termcode(name, s, FALSE);
1280 #   ifdef FEAT_MOUSE_JSB
1281     if (n == KS_JSBTERM_MOUSE)
1282 	has_mouse_termcode |= HMT_JSBTERM;
1283     else
1284 #   endif
1285 #   ifdef FEAT_MOUSE_NET
1286     if (n == KS_NETTERM_MOUSE)
1287 	has_mouse_termcode |= HMT_NETTERM;
1288     else
1289 #   endif
1290 #   ifdef FEAT_MOUSE_DEC
1291     if (n == KS_DEC_MOUSE)
1292 	has_mouse_termcode |= HMT_DEC;
1293     else
1294 #   endif
1295 #   ifdef FEAT_MOUSE_PTERM
1296     if (n == KS_PTERM_MOUSE)
1297 	has_mouse_termcode |= HMT_PTERM;
1298     else
1299 #   endif
1300 #   ifdef FEAT_MOUSE_URXVT
1301     if (n == KS_URXVT_MOUSE)
1302 	has_mouse_termcode |= HMT_URXVT;
1303     else
1304 #   endif
1305 #   ifdef FEAT_MOUSE_GPM
1306     if (n == KS_GPM_MOUSE)
1307 	has_mouse_termcode |= HMT_GPM;
1308     else
1309 #   endif
1310     if (n == KS_SGR_MOUSE)
1311 	has_mouse_termcode |= HMT_SGR;
1312     else if (n == KS_SGR_MOUSE_RELEASE)
1313 	has_mouse_termcode |= HMT_SGR_REL;
1314     else
1315 	has_mouse_termcode |= HMT_NORMAL;
1316 }
1317 
1318 # if defined(UNIX) || defined(VMS) || defined(PROTO)
1319     void
1320 del_mouse_termcode(
1321     int		n)	// KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE
1322 {
1323     char_u	name[2];
1324 
1325     name[0] = n;
1326     name[1] = KE_FILLER;
1327     del_termcode(name);
1328 #   ifdef FEAT_MOUSE_JSB
1329     if (n == KS_JSBTERM_MOUSE)
1330 	has_mouse_termcode &= ~HMT_JSBTERM;
1331     else
1332 #   endif
1333 #   ifdef FEAT_MOUSE_NET
1334     if (n == KS_NETTERM_MOUSE)
1335 	has_mouse_termcode &= ~HMT_NETTERM;
1336     else
1337 #   endif
1338 #   ifdef FEAT_MOUSE_DEC
1339     if (n == KS_DEC_MOUSE)
1340 	has_mouse_termcode &= ~HMT_DEC;
1341     else
1342 #   endif
1343 #   ifdef FEAT_MOUSE_PTERM
1344     if (n == KS_PTERM_MOUSE)
1345 	has_mouse_termcode &= ~HMT_PTERM;
1346     else
1347 #   endif
1348 #   ifdef FEAT_MOUSE_URXVT
1349     if (n == KS_URXVT_MOUSE)
1350 	has_mouse_termcode &= ~HMT_URXVT;
1351     else
1352 #   endif
1353 #   ifdef FEAT_MOUSE_GPM
1354     if (n == KS_GPM_MOUSE)
1355 	has_mouse_termcode &= ~HMT_GPM;
1356     else
1357 #   endif
1358     if (n == KS_SGR_MOUSE)
1359 	has_mouse_termcode &= ~HMT_SGR;
1360     else if (n == KS_SGR_MOUSE_RELEASE)
1361 	has_mouse_termcode &= ~HMT_SGR_REL;
1362     else
1363 	has_mouse_termcode &= ~HMT_NORMAL;
1364 }
1365 # endif
1366 
1367 /*
1368  * setmouse() - switch mouse on/off depending on current mode and 'mouse'
1369  */
1370     void
1371 setmouse(void)
1372 {
1373     int	    checkfor;
1374 
1375 # ifdef FEAT_MOUSESHAPE
1376     update_mouseshape(-1);
1377 # endif
1378 
1379     // Should be outside proc, but may break MOUSESHAPE
1380 #  ifdef FEAT_GUI
1381     // In the GUI the mouse is always enabled.
1382     if (gui.in_use)
1383 	return;
1384 #  endif
1385     // be quick when mouse is off
1386     if (*p_mouse == NUL || has_mouse_termcode == 0)
1387 	return;
1388 
1389     // don't switch mouse on when not in raw mode (Ex mode)
1390     if (cur_tmode != TMODE_RAW)
1391     {
1392 	mch_setmouse(FALSE);
1393 	return;
1394     }
1395 
1396     if (VIsual_active)
1397 	checkfor = MOUSE_VISUAL;
1398     else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE)
1399 	checkfor = MOUSE_RETURN;
1400     else if (State & INSERT)
1401 	checkfor = MOUSE_INSERT;
1402     else if (State & CMDLINE)
1403 	checkfor = MOUSE_COMMAND;
1404     else if (State == CONFIRM || State == EXTERNCMD)
1405 	checkfor = ' '; // don't use mouse for ":confirm" or ":!cmd"
1406     else
1407 	checkfor = MOUSE_NORMAL;    // assume normal mode
1408 
1409     if (mouse_has(checkfor))
1410 	mch_setmouse(TRUE);
1411     else
1412 	mch_setmouse(FALSE);
1413 }
1414 
1415 /*
1416  * Return TRUE if
1417  * - "c" is in 'mouse', or
1418  * - 'a' is in 'mouse' and "c" is in MOUSE_A, or
1419  * - the current buffer is a help file and 'h' is in 'mouse' and we are in a
1420  *   normal editing mode (not at hit-return message).
1421  */
1422     int
1423 mouse_has(int c)
1424 {
1425     char_u	*p;
1426 
1427     for (p = p_mouse; *p; ++p)
1428 	switch (*p)
1429 	{
1430 	    case 'a': if (vim_strchr((char_u *)MOUSE_A, c) != NULL)
1431 			  return TRUE;
1432 		      break;
1433 	    case MOUSE_HELP: if (c != MOUSE_RETURN && curbuf->b_help)
1434 				 return TRUE;
1435 			     break;
1436 	    default: if (c == *p) return TRUE; break;
1437 	}
1438     return FALSE;
1439 }
1440 
1441 /*
1442  * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos".
1443  */
1444     int
1445 mouse_model_popup(void)
1446 {
1447     return (p_mousem[0] == 'p');
1448 }
1449 
1450 /*
1451  * Move the cursor to the specified row and column on the screen.
1452  * Change current window if necessary.	Returns an integer with the
1453  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
1454  *
1455  * The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
1456  * The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
1457  *
1458  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
1459  * if the mouse is outside the window then the text will scroll, or if the
1460  * mouse was previously on a status line, then the status line may be dragged.
1461  *
1462  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
1463  * cursor is moved unless the cursor was on a status line.
1464  * This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
1465  * IN_SEP_LINE depending on where the cursor was clicked.
1466  *
1467  * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
1468  * the mouse is on the status line of the same window.
1469  *
1470  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
1471  * the last call.
1472  *
1473  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
1474  * remembered.
1475  */
1476     int
1477 jump_to_mouse(
1478     int		flags,
1479     int		*inclusive,	// used for inclusive operator, can be NULL
1480     int		which_button)	// MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE
1481 {
1482     static int	on_status_line = 0;	// #lines below bottom of window
1483     static int	on_sep_line = 0;	// on separator right of window
1484 #ifdef FEAT_MENU
1485     static int  in_winbar = FALSE;
1486 #endif
1487 #ifdef FEAT_TEXT_PROP
1488     static int   in_popup_win = FALSE;
1489     static win_T *click_in_popup_win = NULL;
1490 #endif
1491     static int	prev_row = -1;
1492     static int	prev_col = -1;
1493     static win_T *dragwin = NULL;	// window being dragged
1494     static int	did_drag = FALSE;	// drag was noticed
1495 
1496     win_T	*wp, *old_curwin;
1497     pos_T	old_cursor;
1498     int		count;
1499     int		first;
1500     int		row = mouse_row;
1501     int		col = mouse_col;
1502 #ifdef FEAT_FOLDING
1503     int		mouse_char;
1504 #endif
1505 
1506     mouse_past_bottom = FALSE;
1507     mouse_past_eol = FALSE;
1508 
1509     if (flags & MOUSE_RELEASED)
1510     {
1511 	// On button release we may change window focus if positioned on a
1512 	// status line and no dragging happened.
1513 	if (dragwin != NULL && !did_drag)
1514 	    flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
1515 	dragwin = NULL;
1516 	did_drag = FALSE;
1517 #ifdef FEAT_TEXT_PROP
1518 	if (click_in_popup_win != NULL && popup_dragwin == NULL)
1519 	    popup_close_for_mouse_click(click_in_popup_win);
1520 
1521 	popup_dragwin = NULL;
1522 	click_in_popup_win = NULL;
1523 #endif
1524     }
1525 
1526     if ((flags & MOUSE_DID_MOVE)
1527 	    && prev_row == mouse_row
1528 	    && prev_col == mouse_col)
1529     {
1530 retnomove:
1531 	// before moving the cursor for a left click which is NOT in a status
1532 	// line, stop Visual mode
1533 	if (on_status_line)
1534 	    return IN_STATUS_LINE;
1535 	if (on_sep_line)
1536 	    return IN_SEP_LINE;
1537 #ifdef FEAT_MENU
1538 	if (in_winbar)
1539 	{
1540 	    // A quick second click may arrive as a double-click, but we use it
1541 	    // as a second click in the WinBar.
1542 	    if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED))
1543 	    {
1544 		wp = mouse_find_win(&row, &col, FAIL_POPUP);
1545 		if (wp == NULL)
1546 		    return IN_UNKNOWN;
1547 		winbar_click(wp, col);
1548 	    }
1549 	    return IN_OTHER_WIN | MOUSE_WINBAR;
1550 	}
1551 #endif
1552 	if (flags & MOUSE_MAY_STOP_VIS)
1553 	{
1554 	    end_visual_mode();
1555 	    redraw_curbuf_later(INVERTED);	// delete the inversion
1556 	}
1557 #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
1558 	// Continue a modeless selection in another window.
1559 	if (cmdwin_type != 0 && row < curwin->w_winrow)
1560 	    return IN_OTHER_WIN;
1561 #endif
1562 #ifdef FEAT_TEXT_PROP
1563 	// Continue a modeless selection in a popup window or dragging it.
1564 	if (in_popup_win)
1565 	{
1566 	    click_in_popup_win = NULL;  // don't close it on release
1567 	    if (popup_dragwin != NULL)
1568 	    {
1569 		// dragging a popup window
1570 		popup_drag(popup_dragwin);
1571 		return IN_UNKNOWN;
1572 	    }
1573 	    return IN_OTHER_WIN;
1574 	}
1575 #endif
1576 	return IN_BUFFER;
1577     }
1578 
1579     prev_row = mouse_row;
1580     prev_col = mouse_col;
1581 
1582     if (flags & MOUSE_SETPOS)
1583 	goto retnomove;				// ugly goto...
1584 
1585 #ifdef FEAT_FOLDING
1586     // Remember the character under the mouse, it might be a '-' or '+' in the
1587     // fold column.
1588     if (row >= 0 && row < Rows && col >= 0 && col <= Columns
1589 						       && ScreenLines != NULL)
1590 	mouse_char = ScreenLines[LineOffset[row] + col];
1591     else
1592 	mouse_char = ' ';
1593 #endif
1594 
1595     old_curwin = curwin;
1596     old_cursor = curwin->w_cursor;
1597 
1598     if (!(flags & MOUSE_FOCUS))
1599     {
1600 	if (row < 0 || col < 0)			// check if it makes sense
1601 	    return IN_UNKNOWN;
1602 
1603 	// find the window where the row is in and adjust "row" and "col" to be
1604 	// relative to top-left of the window
1605 	wp = mouse_find_win(&row, &col, FIND_POPUP);
1606 	if (wp == NULL)
1607 	    return IN_UNKNOWN;
1608 	dragwin = NULL;
1609 
1610 #ifdef FEAT_TEXT_PROP
1611 	// Click in a popup window may start dragging or modeless selection,
1612 	// but not much else.
1613 	if (WIN_IS_POPUP(wp))
1614 	{
1615 	    on_sep_line = 0;
1616 	    in_popup_win = TRUE;
1617 	    if (which_button == MOUSE_LEFT && popup_close_if_on_X(wp, row, col))
1618 	    {
1619 		return IN_UNKNOWN;
1620 	    }
1621 	    else if ((wp->w_popup_flags & (POPF_DRAG | POPF_RESIZE))
1622 					      && popup_on_border(wp, row, col))
1623 	    {
1624 		popup_dragwin = wp;
1625 		popup_start_drag(wp, row, col);
1626 		return IN_UNKNOWN;
1627 	    }
1628 	    // Only close on release, otherwise it's not possible to drag or do
1629 	    // modeless selection.
1630 	    else if (wp->w_popup_close == POPCLOSE_CLICK
1631 		    && which_button == MOUSE_LEFT)
1632 	    {
1633 		click_in_popup_win = wp;
1634 	    }
1635 	    else if (which_button == MOUSE_LEFT)
1636 		// If the click is in the scrollbar, may scroll up/down.
1637 		popup_handle_scrollbar_click(wp, row, col);
1638 # ifdef FEAT_CLIPBOARD
1639 	    return IN_OTHER_WIN;
1640 # else
1641 	    return IN_UNKNOWN;
1642 # endif
1643 	}
1644 	in_popup_win = FALSE;
1645 	popup_dragwin = NULL;
1646 #endif
1647 #ifdef FEAT_MENU
1648 	if (row == -1)
1649 	{
1650 	    // A click in the window toolbar does not enter another window or
1651 	    // change Visual highlighting.
1652 	    winbar_click(wp, col);
1653 	    in_winbar = TRUE;
1654 	    return IN_OTHER_WIN | MOUSE_WINBAR;
1655 	}
1656 	in_winbar = FALSE;
1657 #endif
1658 
1659 	// winpos and height may change in win_enter()!
1660 	if (row >= wp->w_height)		// In (or below) status line
1661 	{
1662 	    on_status_line = row - wp->w_height + 1;
1663 	    dragwin = wp;
1664 	}
1665 	else
1666 	    on_status_line = 0;
1667 	if (col >= wp->w_width)		// In separator line
1668 	{
1669 	    on_sep_line = col - wp->w_width + 1;
1670 	    dragwin = wp;
1671 	}
1672 	else
1673 	    on_sep_line = 0;
1674 
1675 	// The rightmost character of the status line might be a vertical
1676 	// separator character if there is no connecting window to the right.
1677 	if (on_status_line && on_sep_line)
1678 	{
1679 	    if (stl_connected(wp))
1680 		on_sep_line = 0;
1681 	    else
1682 		on_status_line = 0;
1683 	}
1684 
1685 	// Before jumping to another buffer, or moving the cursor for a left
1686 	// click, stop Visual mode.
1687 	if (VIsual_active
1688 		&& (wp->w_buffer != curwin->w_buffer
1689 		    || (!on_status_line && !on_sep_line
1690 #ifdef FEAT_FOLDING
1691 			&& (
1692 # ifdef FEAT_RIGHTLEFT
1693 			    wp->w_p_rl ? col < wp->w_width - wp->w_p_fdc :
1694 # endif
1695 			    col >= wp->w_p_fdc
1696 # ifdef FEAT_CMDWIN
1697 				  + (cmdwin_type == 0 && wp == curwin ? 0 : 1)
1698 # endif
1699 			    )
1700 #endif
1701 			&& (flags & MOUSE_MAY_STOP_VIS))))
1702 	{
1703 	    end_visual_mode();
1704 	    redraw_curbuf_later(INVERTED);	// delete the inversion
1705 	}
1706 #ifdef FEAT_CMDWIN
1707 	if (cmdwin_type != 0 && wp != curwin)
1708 	{
1709 	    // A click outside the command-line window: Use modeless
1710 	    // selection if possible.  Allow dragging the status lines.
1711 	    on_sep_line = 0;
1712 # ifdef FEAT_CLIPBOARD
1713 	    if (on_status_line)
1714 		return IN_STATUS_LINE;
1715 	    return IN_OTHER_WIN;
1716 # else
1717 	    row = 0;
1718 	    col += wp->w_wincol;
1719 	    wp = curwin;
1720 # endif
1721 	}
1722 #endif
1723 	// Only change window focus when not clicking on or dragging the
1724 	// status line.  Do change focus when releasing the mouse button
1725 	// (MOUSE_FOCUS was set above if we dragged first).
1726 	if (dragwin == NULL || (flags & MOUSE_RELEASED))
1727 	    win_enter(wp, TRUE);		// can make wp invalid!
1728 
1729 	if (curwin != old_curwin)
1730 	{
1731 #ifdef CHECK_DOUBLE_CLICK
1732 	    // set topline, to be able to check for double click ourselves
1733 	    set_mouse_topline(curwin);
1734 #endif
1735 #ifdef FEAT_TERMINAL
1736 	    // when entering a terminal window may change state
1737 	    term_win_entered();
1738 #endif
1739 	}
1740 	if (on_status_line)			// In (or below) status line
1741 	{
1742 	    // Don't use start_arrow() if we're in the same window
1743 	    if (curwin == old_curwin)
1744 		return IN_STATUS_LINE;
1745 	    else
1746 		return IN_STATUS_LINE | CURSOR_MOVED;
1747 	}
1748 	if (on_sep_line)			// In (or below) status line
1749 	{
1750 	    // Don't use start_arrow() if we're in the same window
1751 	    if (curwin == old_curwin)
1752 		return IN_SEP_LINE;
1753 	    else
1754 		return IN_SEP_LINE | CURSOR_MOVED;
1755 	}
1756 
1757 	curwin->w_cursor.lnum = curwin->w_topline;
1758 #ifdef FEAT_GUI
1759 	// remember topline, needed for double click
1760 	gui_prev_topline = curwin->w_topline;
1761 # ifdef FEAT_DIFF
1762 	gui_prev_topfill = curwin->w_topfill;
1763 # endif
1764 #endif
1765     }
1766     else if (on_status_line && which_button == MOUSE_LEFT)
1767     {
1768 	if (dragwin != NULL)
1769 	{
1770 	    // Drag the status line
1771 	    count = row - dragwin->w_winrow - dragwin->w_height + 1
1772 							     - on_status_line;
1773 	    win_drag_status_line(dragwin, count);
1774 	    did_drag |= count;
1775 	}
1776 	return IN_STATUS_LINE;			// Cursor didn't move
1777     }
1778     else if (on_sep_line && which_button == MOUSE_LEFT)
1779     {
1780 	if (dragwin != NULL)
1781 	{
1782 	    // Drag the separator column
1783 	    count = col - dragwin->w_wincol - dragwin->w_width + 1
1784 								- on_sep_line;
1785 	    win_drag_vsep_line(dragwin, count);
1786 	    did_drag |= count;
1787 	}
1788 	return IN_SEP_LINE;			// Cursor didn't move
1789     }
1790 #ifdef FEAT_MENU
1791     else if (in_winbar)
1792     {
1793 	// After a click on the window toolbar don't start Visual mode.
1794 	return IN_OTHER_WIN | MOUSE_WINBAR;
1795     }
1796 #endif
1797     else // keep_window_focus must be TRUE
1798     {
1799 	// before moving the cursor for a left click, stop Visual mode
1800 	if (flags & MOUSE_MAY_STOP_VIS)
1801 	{
1802 	    end_visual_mode();
1803 	    redraw_curbuf_later(INVERTED);	// delete the inversion
1804 	}
1805 
1806 #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
1807 	// Continue a modeless selection in another window.
1808 	if (cmdwin_type != 0 && row < curwin->w_winrow)
1809 	    return IN_OTHER_WIN;
1810 #endif
1811 #ifdef FEAT_TEXT_PROP
1812 	if (in_popup_win)
1813 	{
1814 	    if (popup_dragwin != NULL)
1815 	    {
1816 		// dragging a popup window
1817 		popup_drag(popup_dragwin);
1818 		return IN_UNKNOWN;
1819 	    }
1820 	    // continue a modeless selection in a popup window
1821 	    click_in_popup_win = NULL;
1822 	    return IN_OTHER_WIN;
1823 	}
1824 #endif
1825 
1826 	row -= W_WINROW(curwin);
1827 	col -= curwin->w_wincol;
1828 
1829 	// When clicking beyond the end of the window, scroll the screen.
1830 	// Scroll by however many rows outside the window we are.
1831 	if (row < 0)
1832 	{
1833 	    count = 0;
1834 	    for (first = TRUE; curwin->w_topline > 1; )
1835 	    {
1836 #ifdef FEAT_DIFF
1837 		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
1838 		    ++count;
1839 		else
1840 #endif
1841 		    count += plines(curwin->w_topline - 1);
1842 		if (!first && count > -row)
1843 		    break;
1844 		first = FALSE;
1845 #ifdef FEAT_FOLDING
1846 		(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1847 #endif
1848 #ifdef FEAT_DIFF
1849 		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
1850 		    ++curwin->w_topfill;
1851 		else
1852 #endif
1853 		{
1854 		    --curwin->w_topline;
1855 #ifdef FEAT_DIFF
1856 		    curwin->w_topfill = 0;
1857 #endif
1858 		}
1859 	    }
1860 #ifdef FEAT_DIFF
1861 	    check_topfill(curwin, FALSE);
1862 #endif
1863 	    curwin->w_valid &=
1864 		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
1865 	    redraw_later(VALID);
1866 	    row = 0;
1867 	}
1868 	else if (row >= curwin->w_height)
1869 	{
1870 	    count = 0;
1871 	    for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; )
1872 	    {
1873 #ifdef FEAT_DIFF
1874 		if (curwin->w_topfill > 0)
1875 		    ++count;
1876 		else
1877 #endif
1878 		    count += plines(curwin->w_topline);
1879 		if (!first && count > row - curwin->w_height + 1)
1880 		    break;
1881 		first = FALSE;
1882 #ifdef FEAT_FOLDING
1883 		if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
1884 			&& curwin->w_topline == curbuf->b_ml.ml_line_count)
1885 		    break;
1886 #endif
1887 #ifdef FEAT_DIFF
1888 		if (curwin->w_topfill > 0)
1889 		    --curwin->w_topfill;
1890 		else
1891 #endif
1892 		{
1893 		    ++curwin->w_topline;
1894 #ifdef FEAT_DIFF
1895 		    curwin->w_topfill =
1896 				   diff_check_fill(curwin, curwin->w_topline);
1897 #endif
1898 		}
1899 	    }
1900 #ifdef FEAT_DIFF
1901 	    check_topfill(curwin, FALSE);
1902 #endif
1903 	    redraw_later(VALID);
1904 	    curwin->w_valid &=
1905 		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
1906 	    row = curwin->w_height - 1;
1907 	}
1908 	else if (row == 0)
1909 	{
1910 	    // When dragging the mouse, while the text has been scrolled up as
1911 	    // far as it goes, moving the mouse in the top line should scroll
1912 	    // the text down (done later when recomputing w_topline).
1913 	    if (mouse_dragging > 0
1914 		    && curwin->w_cursor.lnum
1915 				       == curwin->w_buffer->b_ml.ml_line_count
1916 		    && curwin->w_cursor.lnum == curwin->w_topline)
1917 		curwin->w_valid &= ~(VALID_TOPLINE);
1918 	}
1919     }
1920 
1921 #ifdef FEAT_FOLDING
1922     // Check for position outside of the fold column.
1923     if (
1924 # ifdef FEAT_RIGHTLEFT
1925 	    curwin->w_p_rl ? col < curwin->w_width - curwin->w_p_fdc :
1926 # endif
1927 	    col >= curwin->w_p_fdc
1928 #  ifdef FEAT_CMDWIN
1929 				+ (cmdwin_type == 0 ? 0 : 1)
1930 #  endif
1931        )
1932 	mouse_char = ' ';
1933 #endif
1934 
1935     // compute the position in the buffer line from the posn on the screen
1936     if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum, NULL))
1937 	mouse_past_bottom = TRUE;
1938 
1939     // Start Visual mode before coladvance(), for when 'sel' != "old"
1940     if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
1941     {
1942 	check_visual_highlight();
1943 	VIsual = old_cursor;
1944 	VIsual_active = TRUE;
1945 	VIsual_reselect = TRUE;
1946 	// if 'selectmode' contains "mouse", start Select mode
1947 	may_start_select('o');
1948 	setmouse();
1949 	if (p_smd && msg_silent == 0)
1950 	    redraw_cmdline = TRUE;	// show visual mode later
1951     }
1952 
1953     curwin->w_curswant = col;
1954     curwin->w_set_curswant = FALSE;	// May still have been TRUE
1955     if (coladvance(col) == FAIL)	// Mouse click beyond end of line
1956     {
1957 	if (inclusive != NULL)
1958 	    *inclusive = TRUE;
1959 	mouse_past_eol = TRUE;
1960     }
1961     else if (inclusive != NULL)
1962 	*inclusive = FALSE;
1963 
1964     count = IN_BUFFER;
1965     if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
1966 	    || curwin->w_cursor.col != old_cursor.col)
1967 	count |= CURSOR_MOVED;		// Cursor has moved
1968 
1969 # ifdef FEAT_FOLDING
1970     if (mouse_char == '+')
1971 	count |= MOUSE_FOLD_OPEN;
1972     else if (mouse_char != ' ')
1973 	count |= MOUSE_FOLD_CLOSE;
1974 # endif
1975 
1976     return count;
1977 }
1978 
1979 /*
1980  * Mouse scroll wheel: Default action is to scroll three lines, or one page
1981  * when Shift or Ctrl is used.
1982  * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or
1983  * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2)
1984  */
1985     void
1986 nv_mousescroll(cmdarg_T *cap)
1987 {
1988     win_T *old_curwin = curwin, *wp;
1989 
1990     if (mouse_row >= 0 && mouse_col >= 0)
1991     {
1992 	int row, col;
1993 
1994 	row = mouse_row;
1995 	col = mouse_col;
1996 
1997 	// find the window at the pointer coordinates
1998 	wp = mouse_find_win(&row, &col, FIND_POPUP);
1999 	if (wp == NULL)
2000 	    return;
2001 #ifdef FEAT_TEXT_PROP
2002 	if (WIN_IS_POPUP(wp) && !wp->w_has_scrollbar)
2003 	    return;
2004 #endif
2005 	curwin = wp;
2006 	curbuf = curwin->w_buffer;
2007     }
2008 
2009     if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
2010     {
2011 # ifdef FEAT_TERMINAL
2012 	if (term_use_loop())
2013 	    // This window is a terminal window, send the mouse event there.
2014 	    // Set "typed" to FALSE to avoid an endless loop.
2015 	    send_keys_to_term(curbuf->b_term, cap->cmdchar, mod_mask, FALSE);
2016 	else
2017 # endif
2018 	if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
2019 	{
2020 	    (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
2021 	}
2022 	else
2023 	{
2024 	    // Don't scroll more than half the window height.
2025 	    if (curwin->w_height < 6)
2026 	    {
2027 		cap->count1 = curwin->w_height / 2;
2028 		if (cap->count1 == 0)
2029 		    cap->count1 = 1;
2030 	    }
2031 	    else
2032 		cap->count1 = 3;
2033 	    cap->count0 = cap->count1;
2034 	    nv_scroll_line(cap);
2035 	}
2036 #ifdef FEAT_TEXT_PROP
2037 	if (WIN_IS_POPUP(curwin))
2038 	    popup_set_firstline(curwin);
2039 #endif
2040     }
2041 # ifdef FEAT_GUI
2042     else
2043     {
2044 	// Horizontal scroll - only allowed when 'wrap' is disabled
2045 	if (!curwin->w_p_wrap)
2046 	{
2047 	    int val, step = 6;
2048 
2049 	    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
2050 		step = curwin->w_width;
2051 	    val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step);
2052 	    if (val < 0)
2053 		val = 0;
2054 
2055 	    gui_do_horiz_scroll(val, TRUE);
2056 	}
2057     }
2058 # endif
2059 # ifdef FEAT_SYN_HL
2060     if (curwin != old_curwin && curwin->w_p_cul)
2061 	redraw_for_cursorline(curwin);
2062 # endif
2063 
2064     curwin->w_redr_status = TRUE;
2065 
2066     curwin = old_curwin;
2067     curbuf = curwin->w_buffer;
2068 }
2069 
2070 /*
2071  * Mouse clicks and drags.
2072  */
2073     void
2074 nv_mouse(cmdarg_T *cap)
2075 {
2076     (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0);
2077 }
2078 
2079 /*
2080  * Check if typebuf 'tp' contains a terminal mouse code and returns the
2081  * modifiers found in typebuf in 'modifiers'.
2082  */
2083     int
2084 check_termcode_mouse(
2085     char_u	*tp,
2086     int		*slen,
2087     char_u	*key_name,
2088     char_u	*modifiers_start,
2089     int		idx,
2090     int		*modifiers)
2091 {
2092     int		j;
2093     char_u	*p;
2094 # if !defined(UNIX) || defined(FEAT_MOUSE_XTERM) || defined(FEAT_GUI) \
2095     || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE)
2096     char_u	bytes[6];
2097     int		num_bytes;
2098 # endif
2099     int		mouse_code = 0;	    // init for GCC
2100     int		is_click, is_drag;
2101     int		wheel_code = 0;
2102     int		current_button;
2103     static int	held_button = MOUSE_RELEASE;
2104     static int	orig_num_clicks = 1;
2105     static int	orig_mouse_code = 0x0;
2106 # ifdef CHECK_DOUBLE_CLICK
2107     static int	orig_mouse_col = 0;
2108     static int	orig_mouse_row = 0;
2109     static struct timeval  orig_mouse_time = {0, 0};
2110     // time of previous mouse click
2111     struct timeval  mouse_time;		// time of current mouse click
2112     long	timediff;		// elapsed time in msec
2113 # endif
2114 
2115     is_click = is_drag = FALSE;
2116 
2117 # if !defined(UNIX) || defined(FEAT_MOUSE_XTERM) || defined(FEAT_GUI) \
2118     || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE)
2119     if (key_name[0] == KS_MOUSE
2120 #  ifdef FEAT_MOUSE_GPM
2121 	    || key_name[0] == KS_GPM_MOUSE
2122 #  endif
2123        )
2124     {
2125 	/*
2126 	 * For xterm we get "<t_mouse>scr", where
2127 	 *  s == encoded button state:
2128 	 *	   0x20 = left button down
2129 	 *	   0x21 = middle button down
2130 	 *	   0x22 = right button down
2131 	 *	   0x23 = any button release
2132 	 *	   0x60 = button 4 down (scroll wheel down)
2133 	 *	   0x61 = button 5 down (scroll wheel up)
2134 	 *	add 0x04 for SHIFT
2135 	 *	add 0x08 for ALT
2136 	 *	add 0x10 for CTRL
2137 	 *	add 0x20 for mouse drag (0x40 is drag with left button)
2138 	 *	add 0x40 for mouse move (0x80 is move, 0x81 too)
2139 	 *		 0x43 (drag + release) is also move
2140 	 *  c == column + ' ' + 1 == column + 33
2141 	 *  r == row + ' ' + 1 == row + 33
2142 	 *
2143 	 * The coordinates are passed on through global variables.
2144 	 * Ugly, but this avoids trouble with mouse clicks at an
2145 	 * unexpected moment and allows for mapping them.
2146 	 */
2147 	for (;;)
2148 	{
2149 #  ifdef FEAT_GUI
2150 	    if (gui.in_use)
2151 	    {
2152 		// GUI uses more bits for columns > 223
2153 		num_bytes = get_bytes_from_buf(tp + *slen, bytes, 5);
2154 		if (num_bytes == -1)	// not enough coordinates
2155 		    return -1;
2156 		mouse_code = bytes[0];
2157 		mouse_col = 128 * (bytes[1] - ' ' - 1)
2158 		    + bytes[2] - ' ' - 1;
2159 		mouse_row = 128 * (bytes[3] - ' ' - 1)
2160 		    + bytes[4] - ' ' - 1;
2161 	    }
2162 	    else
2163 #  endif
2164 	    {
2165 		num_bytes = get_bytes_from_buf(tp + *slen, bytes, 3);
2166 		if (num_bytes == -1)	// not enough coordinates
2167 		    return -1;
2168 		mouse_code = bytes[0];
2169 		mouse_col = bytes[1] - ' ' - 1;
2170 		mouse_row = bytes[2] - ' ' - 1;
2171 	    }
2172 	    *slen += num_bytes;
2173 
2174 	    // If the following bytes is also a mouse code and it has
2175 	    // the same code, dump this one and get the next.  This
2176 	    // makes dragging a whole lot faster.
2177 #  ifdef FEAT_GUI
2178 	    if (gui.in_use)
2179 		j = 3;
2180 	    else
2181 #  endif
2182 		j = get_termcode_len(idx);
2183 	    if (STRNCMP(tp, tp + *slen, (size_t)j) == 0
2184 		    && tp[*slen + j] == mouse_code
2185 		    && tp[*slen + j + 1] != NUL
2186 		    && tp[*slen + j + 2] != NUL
2187 #  ifdef FEAT_GUI
2188 		    && (!gui.in_use
2189 			|| (tp[*slen + j + 3] != NUL
2190 			    && tp[*slen + j + 4] != NUL))
2191 #  endif
2192 	       )
2193 		*slen += j;
2194 	    else
2195 		break;
2196 	}
2197     }
2198 
2199     if (key_name[0] == KS_URXVT_MOUSE
2200 	    || key_name[0] == KS_SGR_MOUSE
2201 	    || key_name[0] == KS_SGR_MOUSE_RELEASE)
2202     {
2203 	// URXVT 1015 mouse reporting mode:
2204 	// Almost identical to xterm mouse mode, except the values
2205 	// are decimal instead of bytes.
2206 	//
2207 	// \033[%d;%d;%dM
2208 	//	       ^-- row
2209 	//	    ^----- column
2210 	//	 ^-------- code
2211 	//
2212 	// SGR 1006 mouse reporting mode:
2213 	// Almost identical to xterm mouse mode, except the values
2214 	// are decimal instead of bytes.
2215 	//
2216 	// \033[<%d;%d;%dM
2217 	//	       ^-- row
2218 	//	    ^----- column
2219 	//	 ^-------- code
2220 	//
2221 	// \033[<%d;%d;%dm        : mouse release event
2222 	//	       ^-- row
2223 	//	    ^----- column
2224 	//	 ^-------- code
2225 	p = modifiers_start;
2226 	if (p == NULL)
2227 	    return -1;
2228 
2229 	mouse_code = getdigits(&p);
2230 	if (*p++ != ';')
2231 	    return -1;
2232 
2233 	// when mouse reporting is SGR, add 32 to mouse code
2234 	if (key_name[0] == KS_SGR_MOUSE
2235 		|| key_name[0] == KS_SGR_MOUSE_RELEASE)
2236 	    mouse_code += 32;
2237 
2238 	if (key_name[0] == KS_SGR_MOUSE_RELEASE)
2239 	    mouse_code |= MOUSE_RELEASE;
2240 
2241 	mouse_col = getdigits(&p) - 1;
2242 	if (*p++ != ';')
2243 	    return -1;
2244 
2245 	mouse_row = getdigits(&p) - 1;
2246 
2247 	// The modifiers were the mouse coordinates, not the
2248 	// modifier keys (alt/shift/ctrl/meta) state.
2249 	*modifiers = 0;
2250     }
2251 
2252     if (key_name[0] == KS_MOUSE
2253 #  ifdef FEAT_MOUSE_GPM
2254 	    || key_name[0] == KS_GPM_MOUSE
2255 #  endif
2256 #  ifdef FEAT_MOUSE_URXVT
2257 	    || key_name[0] == KS_URXVT_MOUSE
2258 #  endif
2259 	    || key_name[0] == KS_SGR_MOUSE
2260 	    || key_name[0] == KS_SGR_MOUSE_RELEASE)
2261     {
2262 #  if !defined(MSWIN)
2263 	/*
2264 	 * Handle mouse events.
2265 	 * Recognize the xterm mouse wheel, but not in the GUI, the
2266 	 * Linux console with GPM and the MS-DOS or Win32 console
2267 	 * (multi-clicks use >= 0x60).
2268 	 */
2269 	if (mouse_code >= MOUSEWHEEL_LOW
2270 #   ifdef FEAT_GUI
2271 		&& !gui.in_use
2272 #   endif
2273 #   ifdef FEAT_MOUSE_GPM
2274 		&& key_name[0] != KS_GPM_MOUSE
2275 #   endif
2276 	   )
2277 	{
2278 #   if defined(UNIX)
2279 	    if (use_xterm_mouse() > 1 && mouse_code >= 0x80)
2280 		// mouse-move event, using MOUSE_DRAG works
2281 		mouse_code = MOUSE_DRAG;
2282 	    else
2283 #   endif
2284 		// Keep the mouse_code before it's changed, so that we
2285 		// remember that it was a mouse wheel click.
2286 		wheel_code = mouse_code;
2287 	}
2288 #   ifdef FEAT_MOUSE_XTERM
2289 	else if (held_button == MOUSE_RELEASE
2290 #    ifdef FEAT_GUI
2291 		&& !gui.in_use
2292 #    endif
2293 		&& (mouse_code == 0x23 || mouse_code == 0x24
2294 		    || mouse_code == 0x40 || mouse_code == 0x41))
2295 	{
2296 	    // Apparently 0x23 and 0x24 are used by rxvt scroll wheel.
2297 	    // And 0x40 and 0x41 are used by some xterm emulator.
2298 	    wheel_code = mouse_code - (mouse_code >= 0x40 ? 0x40 : 0x23)
2299 		+ MOUSEWHEEL_LOW;
2300 	}
2301 #   endif
2302 
2303 #   if defined(UNIX)
2304 	else if (use_xterm_mouse() > 1)
2305 	{
2306 	    if (mouse_code & MOUSE_DRAG_XTERM)
2307 		mouse_code |= MOUSE_DRAG;
2308 	}
2309 #   endif
2310 #   ifdef FEAT_XCLIPBOARD
2311 	else if (!(mouse_code & MOUSE_DRAG & ~MOUSE_CLICK_MASK))
2312 	{
2313 	    if ((mouse_code & MOUSE_RELEASE) == MOUSE_RELEASE)
2314 		stop_xterm_trace();
2315 	    else
2316 		start_xterm_trace(mouse_code);
2317 	}
2318 #   endif
2319 #  endif
2320     }
2321 # endif // !UNIX || FEAT_MOUSE_XTERM
2322 # ifdef FEAT_MOUSE_NET
2323     if (key_name[0] == KS_NETTERM_MOUSE)
2324     {
2325 	int mc, mr;
2326 
2327 	// expect a rather limited sequence like: balancing {
2328 	// \033}6,45\r
2329 	// '6' is the row, 45 is the column
2330 	p = tp + *slen;
2331 	mr = getdigits(&p);
2332 	if (*p++ != ',')
2333 	    return -1;
2334 	mc = getdigits(&p);
2335 	if (*p++ != '\r')
2336 	    return -1;
2337 
2338 	mouse_col = mc - 1;
2339 	mouse_row = mr - 1;
2340 	mouse_code = MOUSE_LEFT;
2341 	*slen += (int)(p - (tp + *slen));
2342     }
2343 # endif	// FEAT_MOUSE_NET
2344 # ifdef FEAT_MOUSE_JSB
2345     if (key_name[0] == KS_JSBTERM_MOUSE)
2346     {
2347 	int mult, val, iter, button, status;
2348 
2349 	/*
2350 	 * JSBTERM Input Model
2351 	 * \033[0~zw uniq escape sequence
2352 	 * (L-x)  Left button pressed - not pressed x not reporting
2353 	 * (M-x)  Middle button pressed - not pressed x not reporting
2354 	 * (R-x)  Right button pressed - not pressed x not reporting
2355 	 * (SDmdu)  Single , Double click, m mouse move d button down
2356 	 *						   u button up
2357 	 *  ###   X cursor position padded to 3 digits
2358 	 *  ###   Y cursor position padded to 3 digits
2359 	 * (s-x)  SHIFT key pressed - not pressed x not reporting
2360 	 * (c-x)  CTRL key pressed - not pressed x not reporting
2361 	 * \033\\ terminating sequence
2362 	 */
2363 	p = tp + *slen;
2364 	button = mouse_code = 0;
2365 	switch (*p++)
2366 	{
2367 	    case 'L': button = 1; break;
2368 	    case '-': break;
2369 	    case 'x': break; // ignore sequence
2370 	    default:  return -1; // Unknown Result
2371 	}
2372 	switch (*p++)
2373 	{
2374 	    case 'M': button |= 2; break;
2375 	    case '-': break;
2376 	    case 'x': break; // ignore sequence
2377 	    default:  return -1; // Unknown Result
2378 	}
2379 	switch (*p++)
2380 	{
2381 	    case 'R': button |= 4; break;
2382 	    case '-': break;
2383 	    case 'x': break; // ignore sequence
2384 	    default:  return -1; // Unknown Result
2385 	}
2386 	status = *p++;
2387 	for (val = 0, mult = 100, iter = 0; iter < 3; iter++,
2388 		mult /= 10, p++)
2389 	    if (*p >= '0' && *p <= '9')
2390 		val += (*p - '0') * mult;
2391 	    else
2392 		return -1;
2393 	mouse_col = val;
2394 	for (val = 0, mult = 100, iter = 0; iter < 3; iter++,
2395 		mult /= 10, p++)
2396 	    if (*p >= '0' && *p <= '9')
2397 		val += (*p - '0') * mult;
2398 	    else
2399 		return -1;
2400 	mouse_row = val;
2401 	switch (*p++)
2402 	{
2403 	    case 's': button |= 8; break;  // SHIFT key Pressed
2404 	    case '-': break;  // Not Pressed
2405 	    case 'x': break;  // Not Reporting
2406 	    default:  return -1; // Unknown Result
2407 	}
2408 	switch (*p++)
2409 	{
2410 	    case 'c': button |= 16; break;  // CTRL key Pressed
2411 	    case '-': break;  // Not Pressed
2412 	    case 'x': break;  // Not Reporting
2413 	    default:  return -1; // Unknown Result
2414 	}
2415 	if (*p++ != '\033')
2416 	    return -1;
2417 	if (*p++ != '\\')
2418 	    return -1;
2419 	switch (status)
2420 	{
2421 	    case 'D': // Double Click
2422 	    case 'S': // Single Click
2423 		if (button & 1) mouse_code |= MOUSE_LEFT;
2424 		if (button & 2) mouse_code |= MOUSE_MIDDLE;
2425 		if (button & 4) mouse_code |= MOUSE_RIGHT;
2426 		if (button & 8) mouse_code |= MOUSE_SHIFT;
2427 		if (button & 16) mouse_code |= MOUSE_CTRL;
2428 		break;
2429 	    case 'm': // Mouse move
2430 		if (button & 1) mouse_code |= MOUSE_LEFT;
2431 		if (button & 2) mouse_code |= MOUSE_MIDDLE;
2432 		if (button & 4) mouse_code |= MOUSE_RIGHT;
2433 		if (button & 8) mouse_code |= MOUSE_SHIFT;
2434 		if (button & 16) mouse_code |= MOUSE_CTRL;
2435 		if ((button & 7) != 0)
2436 		{
2437 		    held_button = mouse_code;
2438 		    mouse_code |= MOUSE_DRAG;
2439 		}
2440 		is_drag = TRUE;
2441 		showmode();
2442 		break;
2443 	    case 'd': // Button Down
2444 		if (button & 1) mouse_code |= MOUSE_LEFT;
2445 		if (button & 2) mouse_code |= MOUSE_MIDDLE;
2446 		if (button & 4) mouse_code |= MOUSE_RIGHT;
2447 		if (button & 8) mouse_code |= MOUSE_SHIFT;
2448 		if (button & 16) mouse_code |= MOUSE_CTRL;
2449 		break;
2450 	    case 'u': // Button Up
2451 		if (button & 1)
2452 		    mouse_code |= MOUSE_LEFT | MOUSE_RELEASE;
2453 		if (button & 2)
2454 		    mouse_code |= MOUSE_MIDDLE | MOUSE_RELEASE;
2455 		if (button & 4)
2456 		    mouse_code |= MOUSE_RIGHT | MOUSE_RELEASE;
2457 		if (button & 8)
2458 		    mouse_code |= MOUSE_SHIFT;
2459 		if (button & 16)
2460 		    mouse_code |= MOUSE_CTRL;
2461 		break;
2462 	    default: return -1; // Unknown Result
2463 	}
2464 
2465 	*slen += (p - (tp + *slen));
2466     }
2467 # endif // FEAT_MOUSE_JSB
2468 # ifdef FEAT_MOUSE_DEC
2469     if (key_name[0] == KS_DEC_MOUSE)
2470     {
2471 	/*
2472 	 * The DEC Locator Input Model
2473 	 * Netterm delivers the code sequence:
2474 	 *  \033[2;4;24;80&w  (left button down)
2475 	 *  \033[3;0;24;80&w  (left button up)
2476 	 *  \033[6;1;24;80&w  (right button down)
2477 	 *  \033[7;0;24;80&w  (right button up)
2478 	 * CSI Pe ; Pb ; Pr ; Pc ; Pp & w
2479 	 * Pe is the event code
2480 	 * Pb is the button code
2481 	 * Pr is the row coordinate
2482 	 * Pc is the column coordinate
2483 	 * Pp is the third coordinate (page number)
2484 	 * Pe, the event code indicates what event caused this report
2485 	 *    The following event codes are defined:
2486 	 *    0 - request, the terminal received an explicit request
2487 	 *	 for a locator report, but the locator is unavailable
2488 	 *    1 - request, the terminal received an explicit request
2489 	 *	 for a locator report
2490 	 *    2 - left button down
2491 	 *    3 - left button up
2492 	 *    4 - middle button down
2493 	 *    5 - middle button up
2494 	 *    6 - right button down
2495 	 *    7 - right button up
2496 	 *    8 - fourth button down
2497 	 *    9 - fourth button up
2498 	 *    10 - locator outside filter rectangle
2499 	 * Pb, the button code, ASCII decimal 0-15 indicating which
2500 	 *   buttons are down if any. The state of the four buttons
2501 	 *   on the locator correspond to the low four bits of the
2502 	 *   decimal value,
2503 	 *   "1" means button depressed
2504 	 *   0 - no buttons down,
2505 	 *   1 - right,
2506 	 *   2 - middle,
2507 	 *   4 - left,
2508 	 *   8 - fourth
2509 	 * Pr is the row coordinate of the locator position in the page,
2510 	 *   encoded as an ASCII decimal value.
2511 	 *   If Pr is omitted, the locator position is undefined
2512 	 *   (outside the terminal window for example).
2513 	 * Pc is the column coordinate of the locator position in the
2514 	 *   page, encoded as an ASCII decimal value.
2515 	 *   If Pc is omitted, the locator position is undefined
2516 	 *   (outside the terminal window for example).
2517 	 * Pp is the page coordinate of the locator position
2518 	 *   encoded as an ASCII decimal value.
2519 	 *   The page coordinate may be omitted if the locator is on
2520 	 *   page one (the default).  We ignore it anyway.
2521 	 */
2522 	int Pe, Pb, Pr, Pc;
2523 
2524 	p = tp + *slen;
2525 
2526 	// get event status
2527 	Pe = getdigits(&p);
2528 	if (*p++ != ';')
2529 	    return -1;
2530 
2531 	// get button status
2532 	Pb = getdigits(&p);
2533 	if (*p++ != ';')
2534 	    return -1;
2535 
2536 	// get row status
2537 	Pr = getdigits(&p);
2538 	if (*p++ != ';')
2539 	    return -1;
2540 
2541 	// get column status
2542 	Pc = getdigits(&p);
2543 
2544 	// the page parameter is optional
2545 	if (*p == ';')
2546 	{
2547 	    p++;
2548 	    (void)getdigits(&p);
2549 	}
2550 	if (*p++ != '&')
2551 	    return -1;
2552 	if (*p++ != 'w')
2553 	    return -1;
2554 
2555 	mouse_code = 0;
2556 	switch (Pe)
2557 	{
2558 	    case  0: return -1; // position request while unavailable
2559 	    case  1: // a response to a locator position request includes
2560 		     //	the status of all buttons
2561 		     Pb &= 7;   // mask off and ignore fourth button
2562 		     if (Pb & 4)
2563 			 mouse_code  = MOUSE_LEFT;
2564 		     if (Pb & 2)
2565 			 mouse_code  = MOUSE_MIDDLE;
2566 		     if (Pb & 1)
2567 			 mouse_code  = MOUSE_RIGHT;
2568 		     if (Pb)
2569 		     {
2570 			 held_button = mouse_code;
2571 			 mouse_code |= MOUSE_DRAG;
2572 			 WantQueryMouse = TRUE;
2573 		     }
2574 		     is_drag = TRUE;
2575 		     showmode();
2576 		     break;
2577 	    case  2: mouse_code = MOUSE_LEFT;
2578 		     WantQueryMouse = TRUE;
2579 		     break;
2580 	    case  3: mouse_code = MOUSE_RELEASE | MOUSE_LEFT;
2581 		     break;
2582 	    case  4: mouse_code = MOUSE_MIDDLE;
2583 		     WantQueryMouse = TRUE;
2584 		     break;
2585 	    case  5: mouse_code = MOUSE_RELEASE | MOUSE_MIDDLE;
2586 		     break;
2587 	    case  6: mouse_code = MOUSE_RIGHT;
2588 		     WantQueryMouse = TRUE;
2589 		     break;
2590 	    case  7: mouse_code = MOUSE_RELEASE | MOUSE_RIGHT;
2591 		     break;
2592 	    case  8: return -1; // fourth button down
2593 	    case  9: return -1; // fourth button up
2594 	    case 10: return -1; // mouse outside of filter rectangle
2595 	    default: return -1; // should never occur
2596 	}
2597 
2598 	mouse_col = Pc - 1;
2599 	mouse_row = Pr - 1;
2600 
2601 	*slen += (int)(p - (tp + *slen));
2602     }
2603 # endif // FEAT_MOUSE_DEC
2604 # ifdef FEAT_MOUSE_PTERM
2605     if (key_name[0] == KS_PTERM_MOUSE)
2606     {
2607 	int button, num_clicks, action;
2608 
2609 	p = tp + *slen;
2610 
2611 	action = getdigits(&p);
2612 	if (*p++ != ';')
2613 	    return -1;
2614 
2615 	mouse_row = getdigits(&p);
2616 	if (*p++ != ';')
2617 	    return -1;
2618 	mouse_col = getdigits(&p);
2619 	if (*p++ != ';')
2620 	    return -1;
2621 
2622 	button = getdigits(&p);
2623 	mouse_code = 0;
2624 
2625 	switch (button)
2626 	{
2627 	    case 4: mouse_code = MOUSE_LEFT; break;
2628 	    case 1: mouse_code = MOUSE_RIGHT; break;
2629 	    case 2: mouse_code = MOUSE_MIDDLE; break;
2630 	    default: return -1;
2631 	}
2632 
2633 	switch (action)
2634 	{
2635 	    case 31: // Initial press
2636 		if (*p++ != ';')
2637 		    return -1;
2638 
2639 		num_clicks = getdigits(&p); // Not used
2640 		break;
2641 
2642 	    case 32: // Release
2643 		mouse_code |= MOUSE_RELEASE;
2644 		break;
2645 
2646 	    case 33: // Drag
2647 		held_button = mouse_code;
2648 		mouse_code |= MOUSE_DRAG;
2649 		break;
2650 
2651 	    default:
2652 		return -1;
2653 	}
2654 
2655 	if (*p++ != 't')
2656 	    return -1;
2657 
2658 	*slen += (p - (tp + *slen));
2659     }
2660 # endif // FEAT_MOUSE_PTERM
2661 
2662     // Interpret the mouse code
2663     current_button = (mouse_code & MOUSE_CLICK_MASK);
2664     if (current_button == MOUSE_RELEASE
2665 # ifdef FEAT_MOUSE_XTERM
2666 	    && wheel_code == 0
2667 # endif
2668        )
2669     {
2670 	/*
2671 	 * If we get a mouse drag or release event when
2672 	 * there is no mouse button held down (held_button ==
2673 	 * MOUSE_RELEASE), produce a K_IGNORE below.
2674 	 * (can happen when you hold down two buttons
2675 	 * and then let them go, or click in the menu bar, but not
2676 	 * on a menu, and drag into the text).
2677 	 */
2678 	if ((mouse_code & MOUSE_DRAG) == MOUSE_DRAG)
2679 	    is_drag = TRUE;
2680 	current_button = held_button;
2681     }
2682     else if (wheel_code == 0)
2683     {
2684 # ifdef CHECK_DOUBLE_CLICK
2685 #  ifdef FEAT_MOUSE_GPM
2686 	/*
2687 	 * Only for Unix, when GUI not active, we handle
2688 	 * multi-clicks here, but not for GPM mouse events.
2689 	 */
2690 #   ifdef FEAT_GUI
2691 	if (key_name[0] != KS_GPM_MOUSE && !gui.in_use)
2692 #   else
2693 	    if (key_name[0] != KS_GPM_MOUSE)
2694 #   endif
2695 #  else
2696 #   ifdef FEAT_GUI
2697 		if (!gui.in_use)
2698 #   endif
2699 #  endif
2700 		{
2701 		    /*
2702 		     * Compute the time elapsed since the previous mouse click.
2703 		     */
2704 		    gettimeofday(&mouse_time, NULL);
2705 		    if (orig_mouse_time.tv_sec == 0)
2706 		    {
2707 			/*
2708 			 * Avoid computing the difference between mouse_time
2709 			 * and orig_mouse_time for the first click, as the
2710 			 * difference would be huge and would cause
2711 			 * multiplication overflow.
2712 			 */
2713 			timediff = p_mouset;
2714 		    }
2715 		    else
2716 		    {
2717 			timediff = (mouse_time.tv_usec
2718 				- orig_mouse_time.tv_usec) / 1000;
2719 			if (timediff < 0)
2720 			    --orig_mouse_time.tv_sec;
2721 			timediff += (mouse_time.tv_sec
2722 				- orig_mouse_time.tv_sec) * 1000;
2723 		    }
2724 		    orig_mouse_time = mouse_time;
2725 		    if (mouse_code == orig_mouse_code
2726 			    && timediff < p_mouset
2727 			    && orig_num_clicks != 4
2728 			    && orig_mouse_col == mouse_col
2729 			    && orig_mouse_row == mouse_row
2730 			    && (is_mouse_topline(curwin)
2731 				// Double click in tab pages line also works
2732 				// when window contents changes.
2733 				|| (mouse_row == 0 && firstwin->w_winrow > 0))
2734 		       )
2735 			++orig_num_clicks;
2736 		    else
2737 			orig_num_clicks = 1;
2738 		    orig_mouse_col = mouse_col;
2739 		    orig_mouse_row = mouse_row;
2740 		    set_mouse_topline(curwin);
2741 		}
2742 #  if defined(FEAT_GUI) || defined(FEAT_MOUSE_GPM)
2743 		else
2744 		    orig_num_clicks = NUM_MOUSE_CLICKS(mouse_code);
2745 #  endif
2746 # else
2747 	orig_num_clicks = NUM_MOUSE_CLICKS(mouse_code);
2748 # endif
2749 	is_click = TRUE;
2750 	orig_mouse_code = mouse_code;
2751     }
2752     if (!is_drag)
2753 	held_button = mouse_code & MOUSE_CLICK_MASK;
2754 
2755     /*
2756      * Translate the actual mouse event into a pseudo mouse event.
2757      * First work out what modifiers are to be used.
2758      */
2759     if (orig_mouse_code & MOUSE_SHIFT)
2760 	*modifiers |= MOD_MASK_SHIFT;
2761     if (orig_mouse_code & MOUSE_CTRL)
2762 	*modifiers |= MOD_MASK_CTRL;
2763     if (orig_mouse_code & MOUSE_ALT)
2764 	*modifiers |= MOD_MASK_ALT;
2765     if (orig_num_clicks == 2)
2766 	*modifiers |= MOD_MASK_2CLICK;
2767     else if (orig_num_clicks == 3)
2768 	*modifiers |= MOD_MASK_3CLICK;
2769     else if (orig_num_clicks == 4)
2770 	*modifiers |= MOD_MASK_4CLICK;
2771 
2772     // Work out our pseudo mouse event. Note that MOUSE_RELEASE gets
2773     // added, then it's not mouse up/down.
2774     key_name[0] = KS_EXTRA;
2775     if (wheel_code != 0
2776 	    && (wheel_code & MOUSE_RELEASE) != MOUSE_RELEASE)
2777     {
2778 	if (wheel_code & MOUSE_CTRL)
2779 	    *modifiers |= MOD_MASK_CTRL;
2780 	if (wheel_code & MOUSE_ALT)
2781 	    *modifiers |= MOD_MASK_ALT;
2782 	key_name[1] = (wheel_code & 1)
2783 	    ? (int)KE_MOUSEUP : (int)KE_MOUSEDOWN;
2784 	held_button = MOUSE_RELEASE;
2785     }
2786     else
2787 	key_name[1] = get_pseudo_mouse_code(current_button,
2788 		is_click, is_drag);
2789 
2790     // Make sure the mouse position is valid.  Some terminals may
2791     // return weird values.
2792     if (mouse_col >= Columns)
2793 	mouse_col = Columns - 1;
2794     if (mouse_row >= Rows)
2795 	mouse_row = Rows - 1;
2796 
2797     return 0;
2798 }
2799 
2800 // Functions also used for popup windows.
2801 
2802 /*
2803  * Compute the buffer line position from the screen position "rowp" / "colp" in
2804  * window "win".
2805  * "plines_cache" can be NULL (no cache) or an array with "win->w_height"
2806  * entries that caches the plines_win() result from a previous call.  Entry is
2807  * zero if not computed yet.  There must be no text or setting changes since
2808  * the entry is put in the cache.
2809  * Returns TRUE if the position is below the last line.
2810  */
2811     int
2812 mouse_comp_pos(
2813     win_T	*win,
2814     int		*rowp,
2815     int		*colp,
2816     linenr_T	*lnump,
2817     int		*plines_cache)
2818 {
2819     int		col = *colp;
2820     int		row = *rowp;
2821     linenr_T	lnum;
2822     int		retval = FALSE;
2823     int		off;
2824     int		count;
2825 
2826 #ifdef FEAT_RIGHTLEFT
2827     if (win->w_p_rl)
2828 	col = win->w_width - 1 - col;
2829 #endif
2830 
2831     lnum = win->w_topline;
2832 
2833     while (row > 0)
2834     {
2835 	int cache_idx = lnum - win->w_topline;
2836 
2837 	if (plines_cache != NULL && plines_cache[cache_idx] > 0)
2838 	    count = plines_cache[cache_idx];
2839 	else
2840 	{
2841 #ifdef FEAT_DIFF
2842 	    // Don't include filler lines in "count"
2843 	    if (win->w_p_diff
2844 # ifdef FEAT_FOLDING
2845 		    && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL)
2846 # endif
2847 		    )
2848 	    {
2849 		if (lnum == win->w_topline)
2850 		    row -= win->w_topfill;
2851 		else
2852 		    row -= diff_check_fill(win, lnum);
2853 		count = plines_win_nofill(win, lnum, TRUE);
2854 	    }
2855 	    else
2856 #endif
2857 		count = plines_win(win, lnum, TRUE);
2858 	    if (plines_cache != NULL)
2859 		plines_cache[cache_idx] = count;
2860 	}
2861 	if (count > row)
2862 	    break;	// Position is in this buffer line.
2863 #ifdef FEAT_FOLDING
2864 	(void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL);
2865 #endif
2866 	if (lnum == win->w_buffer->b_ml.ml_line_count)
2867 	{
2868 	    retval = TRUE;
2869 	    break;		// past end of file
2870 	}
2871 	row -= count;
2872 	++lnum;
2873     }
2874 
2875     if (!retval)
2876     {
2877 	// Compute the column without wrapping.
2878 	off = win_col_off(win) - win_col_off2(win);
2879 	if (col < off)
2880 	    col = off;
2881 	col += row * (win->w_width - off);
2882 	// add skip column (for long wrapping line)
2883 	col += win->w_skipcol;
2884     }
2885 
2886     if (!win->w_p_wrap)
2887 	col += win->w_leftcol;
2888 
2889     // skip line number and fold column in front of the line
2890     col -= win_col_off(win);
2891     if (col < 0)
2892     {
2893 #ifdef FEAT_NETBEANS_INTG
2894 	netbeans_gutter_click(lnum);
2895 #endif
2896 	col = 0;
2897     }
2898 
2899     *colp = col;
2900     *rowp = row;
2901     *lnump = lnum;
2902     return retval;
2903 }
2904 
2905 /*
2906  * Find the window at screen position "*rowp" and "*colp".  The positions are
2907  * updated to become relative to the top-left of the window.
2908  * When "popup" is FAIL_POPUP and the position is in a popup window then NULL
2909  * is returned.  When "popup" is IGNORE_POPUP then do not even check popup
2910  * windows.
2911  * Returns NULL when something is wrong.
2912  */
2913     win_T *
2914 mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
2915 {
2916     frame_T	*fp;
2917     win_T	*wp;
2918 
2919 #ifdef FEAT_TEXT_PROP
2920     win_T	*pwp = NULL;
2921 
2922     if (popup != IGNORE_POPUP)
2923     {
2924 	popup_reset_handled(POPUP_HANDLED_1);
2925 	while ((wp = find_next_popup(TRUE, POPUP_HANDLED_1)) != NULL)
2926 	{
2927 	    if (*rowp >= wp->w_winrow && *rowp < wp->w_winrow + popup_height(wp)
2928 		    && *colp >= wp->w_wincol
2929 				    && *colp < wp->w_wincol + popup_width(wp))
2930 		pwp = wp;
2931 	}
2932 	if (pwp != NULL)
2933 	{
2934 	    if (popup == FAIL_POPUP)
2935 		return NULL;
2936 	    *rowp -= pwp->w_winrow;
2937 	    *colp -= pwp->w_wincol;
2938 	    return pwp;
2939 	}
2940     }
2941 #endif
2942 
2943     fp = topframe;
2944     *rowp -= firstwin->w_winrow;
2945     for (;;)
2946     {
2947 	if (fp->fr_layout == FR_LEAF)
2948 	    break;
2949 	if (fp->fr_layout == FR_ROW)
2950 	{
2951 	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
2952 	    {
2953 		if (*colp < fp->fr_width)
2954 		    break;
2955 		*colp -= fp->fr_width;
2956 	    }
2957 	}
2958 	else    // fr_layout == FR_COL
2959 	{
2960 	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
2961 	    {
2962 		if (*rowp < fp->fr_height)
2963 		    break;
2964 		*rowp -= fp->fr_height;
2965 	    }
2966 	}
2967     }
2968     // When using a timer that closes a window the window might not actually
2969     // exist.
2970     FOR_ALL_WINDOWS(wp)
2971 	if (wp == fp->fr_win)
2972 	{
2973 #ifdef FEAT_MENU
2974 	    *rowp -= wp->w_winbar_height;
2975 #endif
2976 	    return wp;
2977 	}
2978     return NULL;
2979 }
2980 
2981 #if defined(NEED_VCOL2COL) || defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) \
2982 	|| defined(PROTO)
2983 /*
2984  * Convert a virtual (screen) column to a character column.
2985  * The first column is one.
2986  */
2987     int
2988 vcol2col(win_T *wp, linenr_T lnum, int vcol)
2989 {
2990     // try to advance to the specified column
2991     int		count = 0;
2992     char_u	*ptr;
2993     char_u	*line;
2994 
2995     line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
2996     while (count < vcol && *ptr != NUL)
2997     {
2998 	count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
2999 	MB_PTR_ADV(ptr);
3000     }
3001     return (int)(ptr - line);
3002 }
3003 #endif
3004