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