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