0
0
mirror of https://github.com/vim/vim.git synced 2025-10-14 07:04:10 -04:00

patch 8.1.2062: the mouse code is spread out

Problem:    The mouse code is spread out.
Solution:   Move all the mouse code to mouse.c. (Yegappan Lakshmanan,
            closes #4959)
This commit is contained in:
Bram Moolenaar
2019-09-21 20:48:04 +02:00
parent 4d5c12626c
commit b20b9e14dd
35 changed files with 2415 additions and 2490 deletions

791
src/ui.c
View File

@@ -2917,797 +2917,6 @@ yank_cut_buffer0(Display *dpy, Clipboard_T *cbd)
}
#endif
#if defined(FEAT_MOUSE) || defined(PROTO)
/*
* Move the cursor to the specified row and column on the screen.
* Change current window if necessary. Returns an integer with the
* CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
*
* The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
* The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
*
* If flags has MOUSE_FOCUS, then the current window will not be changed, and
* if the mouse is outside the window then the text will scroll, or if the
* mouse was previously on a status line, then the status line may be dragged.
*
* If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
* cursor is moved unless the cursor was on a status line.
* This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
* IN_SEP_LINE depending on where the cursor was clicked.
*
* If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
* the mouse is on the status line of the same window.
*
* If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
* the last call.
*
* If flags has MOUSE_SETPOS, nothing is done, only the current position is
* remembered.
*/
int
jump_to_mouse(
int flags,
int *inclusive, /* used for inclusive operator, can be NULL */
int which_button) /* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */
{
static int on_status_line = 0; /* #lines below bottom of window */
static int on_sep_line = 0; /* on separator right of window */
#ifdef FEAT_MENU
static int in_winbar = FALSE;
#endif
#ifdef FEAT_TEXT_PROP
static int in_popup_win = FALSE;
static win_T *click_in_popup_win = NULL;
#endif
static int prev_row = -1;
static int prev_col = -1;
static win_T *dragwin = NULL; /* window being dragged */
static int did_drag = FALSE; /* drag was noticed */
win_T *wp, *old_curwin;
pos_T old_cursor;
int count;
int first;
int row = mouse_row;
int col = mouse_col;
#ifdef FEAT_FOLDING
int mouse_char;
#endif
mouse_past_bottom = FALSE;
mouse_past_eol = FALSE;
if (flags & MOUSE_RELEASED)
{
/* On button release we may change window focus if positioned on a
* status line and no dragging happened. */
if (dragwin != NULL && !did_drag)
flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
dragwin = NULL;
did_drag = FALSE;
#ifdef FEAT_TEXT_PROP
if (click_in_popup_win != NULL && popup_dragwin == NULL)
popup_close_for_mouse_click(click_in_popup_win);
popup_dragwin = NULL;
click_in_popup_win = NULL;
#endif
}
if ((flags & MOUSE_DID_MOVE)
&& prev_row == mouse_row
&& prev_col == mouse_col)
{
retnomove:
/* before moving the cursor for a left click which is NOT in a status
* line, stop Visual mode */
if (on_status_line)
return IN_STATUS_LINE;
if (on_sep_line)
return IN_SEP_LINE;
#ifdef FEAT_MENU
if (in_winbar)
{
/* A quick second click may arrive as a double-click, but we use it
* as a second click in the WinBar. */
if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED))
{
wp = mouse_find_win(&row, &col, FAIL_POPUP);
if (wp == NULL)
return IN_UNKNOWN;
winbar_click(wp, col);
}
return IN_OTHER_WIN | MOUSE_WINBAR;
}
#endif
if (flags & MOUSE_MAY_STOP_VIS)
{
end_visual_mode();
redraw_curbuf_later(INVERTED); /* delete the inversion */
}
#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
// Continue a modeless selection in another window.
if (cmdwin_type != 0 && row < curwin->w_winrow)
return IN_OTHER_WIN;
#endif
#ifdef FEAT_TEXT_PROP
// Continue a modeless selection in a popup window or dragging it.
if (in_popup_win)
{
click_in_popup_win = NULL; // don't close it on release
if (popup_dragwin != NULL)
{
// dragging a popup window
popup_drag(popup_dragwin);
return IN_UNKNOWN;
}
return IN_OTHER_WIN;
}
#endif
return IN_BUFFER;
}
prev_row = mouse_row;
prev_col = mouse_col;
if (flags & MOUSE_SETPOS)
goto retnomove; /* ugly goto... */
#ifdef FEAT_FOLDING
/* Remember the character under the mouse, it might be a '-' or '+' in the
* fold column. */
if (row >= 0 && row < Rows && col >= 0 && col <= Columns
&& ScreenLines != NULL)
mouse_char = ScreenLines[LineOffset[row] + col];
else
mouse_char = ' ';
#endif
old_curwin = curwin;
old_cursor = curwin->w_cursor;
if (!(flags & MOUSE_FOCUS))
{
if (row < 0 || col < 0) // check if it makes sense
return IN_UNKNOWN;
// find the window where the row is in and adjust "row" and "col" to be
// relative to top-left of the window
wp = mouse_find_win(&row, &col, FIND_POPUP);
if (wp == NULL)
return IN_UNKNOWN;
dragwin = NULL;
#ifdef FEAT_TEXT_PROP
// Click in a popup window may start dragging or modeless selection,
// but not much else.
if (WIN_IS_POPUP(wp))
{
on_sep_line = 0;
in_popup_win = TRUE;
if (which_button == MOUSE_LEFT && popup_close_if_on_X(wp, row, col))
{
return IN_UNKNOWN;
}
else if ((wp->w_popup_flags & (POPF_DRAG | POPF_RESIZE))
&& popup_on_border(wp, row, col))
{
popup_dragwin = wp;
popup_start_drag(wp, row, col);
return IN_UNKNOWN;
}
// Only close on release, otherwise it's not possible to drag or do
// modeless selection.
else if (wp->w_popup_close == POPCLOSE_CLICK
&& which_button == MOUSE_LEFT)
{
click_in_popup_win = wp;
}
else if (which_button == MOUSE_LEFT)
// If the click is in the scrollbar, may scroll up/down.
popup_handle_scrollbar_click(wp, row, col);
# ifdef FEAT_CLIPBOARD
return IN_OTHER_WIN;
# else
return IN_UNKNOWN;
# endif
}
in_popup_win = FALSE;
popup_dragwin = NULL;
#endif
#ifdef FEAT_MENU
if (row == -1)
{
/* A click in the window toolbar does not enter another window or
* change Visual highlighting. */
winbar_click(wp, col);
in_winbar = TRUE;
return IN_OTHER_WIN | MOUSE_WINBAR;
}
in_winbar = FALSE;
#endif
/*
* winpos and height may change in win_enter()!
*/
if (row >= wp->w_height) /* In (or below) status line */
{
on_status_line = row - wp->w_height + 1;
dragwin = wp;
}
else
on_status_line = 0;
if (col >= wp->w_width) /* In separator line */
{
on_sep_line = col - wp->w_width + 1;
dragwin = wp;
}
else
on_sep_line = 0;
/* The rightmost character of the status line might be a vertical
* separator character if there is no connecting window to the right. */
if (on_status_line && on_sep_line)
{
if (stl_connected(wp))
on_sep_line = 0;
else
on_status_line = 0;
}
/* Before jumping to another buffer, or moving the cursor for a left
* click, stop Visual mode. */
if (VIsual_active
&& (wp->w_buffer != curwin->w_buffer
|| (!on_status_line && !on_sep_line
#ifdef FEAT_FOLDING
&& (
# ifdef FEAT_RIGHTLEFT
wp->w_p_rl ? col < wp->w_width - wp->w_p_fdc :
# endif
col >= wp->w_p_fdc
# ifdef FEAT_CMDWIN
+ (cmdwin_type == 0 && wp == curwin ? 0 : 1)
# endif
)
#endif
&& (flags & MOUSE_MAY_STOP_VIS))))
{
end_visual_mode();
redraw_curbuf_later(INVERTED); /* delete the inversion */
}
#ifdef FEAT_CMDWIN
if (cmdwin_type != 0 && wp != curwin)
{
/* A click outside the command-line window: Use modeless
* selection if possible. Allow dragging the status lines. */
on_sep_line = 0;
# ifdef FEAT_CLIPBOARD
if (on_status_line)
return IN_STATUS_LINE;
return IN_OTHER_WIN;
# else
row = 0;
col += wp->w_wincol;
wp = curwin;
# endif
}
#endif
/* Only change window focus when not clicking on or dragging the
* status line. Do change focus when releasing the mouse button
* (MOUSE_FOCUS was set above if we dragged first). */
if (dragwin == NULL || (flags & MOUSE_RELEASED))
win_enter(wp, TRUE); /* can make wp invalid! */
if (curwin != old_curwin)
{
#ifdef CHECK_DOUBLE_CLICK
/* set topline, to be able to check for double click ourselves */
set_mouse_topline(curwin);
#endif
#ifdef FEAT_TERMINAL
/* when entering a terminal window may change state */
term_win_entered();
#endif
}
if (on_status_line) /* In (or below) status line */
{
/* Don't use start_arrow() if we're in the same window */
if (curwin == old_curwin)
return IN_STATUS_LINE;
else
return IN_STATUS_LINE | CURSOR_MOVED;
}
if (on_sep_line) /* In (or below) status line */
{
/* Don't use start_arrow() if we're in the same window */
if (curwin == old_curwin)
return IN_SEP_LINE;
else
return IN_SEP_LINE | CURSOR_MOVED;
}
curwin->w_cursor.lnum = curwin->w_topline;
#ifdef FEAT_GUI
/* remember topline, needed for double click */
gui_prev_topline = curwin->w_topline;
# ifdef FEAT_DIFF
gui_prev_topfill = curwin->w_topfill;
# endif
#endif
}
else if (on_status_line && which_button == MOUSE_LEFT)
{
if (dragwin != NULL)
{
/* Drag the status line */
count = row - dragwin->w_winrow - dragwin->w_height + 1
- on_status_line;
win_drag_status_line(dragwin, count);
did_drag |= count;
}
return IN_STATUS_LINE; /* Cursor didn't move */
}
else if (on_sep_line && which_button == MOUSE_LEFT)
{
if (dragwin != NULL)
{
/* Drag the separator column */
count = col - dragwin->w_wincol - dragwin->w_width + 1
- on_sep_line;
win_drag_vsep_line(dragwin, count);
did_drag |= count;
}
return IN_SEP_LINE; /* Cursor didn't move */
}
#ifdef FEAT_MENU
else if (in_winbar)
{
/* After a click on the window toolbar don't start Visual mode. */
return IN_OTHER_WIN | MOUSE_WINBAR;
}
#endif
else /* keep_window_focus must be TRUE */
{
/* before moving the cursor for a left click, stop Visual mode */
if (flags & MOUSE_MAY_STOP_VIS)
{
end_visual_mode();
redraw_curbuf_later(INVERTED); /* delete the inversion */
}
#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
/* Continue a modeless selection in another window. */
if (cmdwin_type != 0 && row < curwin->w_winrow)
return IN_OTHER_WIN;
#endif
#ifdef FEAT_TEXT_PROP
if (in_popup_win)
{
if (popup_dragwin != NULL)
{
// dragging a popup window
popup_drag(popup_dragwin);
return IN_UNKNOWN;
}
// continue a modeless selection in a popup window
click_in_popup_win = NULL;
return IN_OTHER_WIN;
}
#endif
row -= W_WINROW(curwin);
col -= curwin->w_wincol;
/*
* When clicking beyond the end of the window, scroll the screen.
* Scroll by however many rows outside the window we are.
*/
if (row < 0)
{
count = 0;
for (first = TRUE; curwin->w_topline > 1; )
{
#ifdef FEAT_DIFF
if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
++count;
else
#endif
count += plines(curwin->w_topline - 1);
if (!first && count > -row)
break;
first = FALSE;
#ifdef FEAT_FOLDING
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
#endif
#ifdef FEAT_DIFF
if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
++curwin->w_topfill;
else
#endif
{
--curwin->w_topline;
#ifdef FEAT_DIFF
curwin->w_topfill = 0;
#endif
}
}
#ifdef FEAT_DIFF
check_topfill(curwin, FALSE);
#endif
curwin->w_valid &=
~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
redraw_later(VALID);
row = 0;
}
else if (row >= curwin->w_height)
{
count = 0;
for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; )
{
#ifdef FEAT_DIFF
if (curwin->w_topfill > 0)
++count;
else
#endif
count += plines(curwin->w_topline);
if (!first && count > row - curwin->w_height + 1)
break;
first = FALSE;
#ifdef FEAT_FOLDING
if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
&& curwin->w_topline == curbuf->b_ml.ml_line_count)
break;
#endif
#ifdef FEAT_DIFF
if (curwin->w_topfill > 0)
--curwin->w_topfill;
else
#endif
{
++curwin->w_topline;
#ifdef FEAT_DIFF
curwin->w_topfill =
diff_check_fill(curwin, curwin->w_topline);
#endif
}
}
#ifdef FEAT_DIFF
check_topfill(curwin, FALSE);
#endif
redraw_later(VALID);
curwin->w_valid &=
~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
row = curwin->w_height - 1;
}
else if (row == 0)
{
/* When dragging the mouse, while the text has been scrolled up as
* far as it goes, moving the mouse in the top line should scroll
* the text down (done later when recomputing w_topline). */
if (mouse_dragging > 0
&& curwin->w_cursor.lnum
== curwin->w_buffer->b_ml.ml_line_count
&& curwin->w_cursor.lnum == curwin->w_topline)
curwin->w_valid &= ~(VALID_TOPLINE);
}
}
#ifdef FEAT_FOLDING
/* Check for position outside of the fold column. */
if (
# ifdef FEAT_RIGHTLEFT
curwin->w_p_rl ? col < curwin->w_width - curwin->w_p_fdc :
# endif
col >= curwin->w_p_fdc
# ifdef FEAT_CMDWIN
+ (cmdwin_type == 0 ? 0 : 1)
# endif
)
mouse_char = ' ';
#endif
/* compute the position in the buffer line from the posn on the screen */
if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum, NULL))
mouse_past_bottom = TRUE;
/* Start Visual mode before coladvance(), for when 'sel' != "old" */
if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
{
check_visual_highlight();
VIsual = old_cursor;
VIsual_active = TRUE;
VIsual_reselect = TRUE;
/* if 'selectmode' contains "mouse", start Select mode */
may_start_select('o');
setmouse();
if (p_smd && msg_silent == 0)
redraw_cmdline = TRUE; /* show visual mode later */
}
curwin->w_curswant = col;
curwin->w_set_curswant = FALSE; /* May still have been TRUE */
if (coladvance(col) == FAIL) /* Mouse click beyond end of line */
{
if (inclusive != NULL)
*inclusive = TRUE;
mouse_past_eol = TRUE;
}
else if (inclusive != NULL)
*inclusive = FALSE;
count = IN_BUFFER;
if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
|| curwin->w_cursor.col != old_cursor.col)
count |= CURSOR_MOVED; /* Cursor has moved */
# ifdef FEAT_FOLDING
if (mouse_char == '+')
count |= MOUSE_FOLD_OPEN;
else if (mouse_char != ' ')
count |= MOUSE_FOLD_CLOSE;
# endif
return count;
}
#endif
// Functions also used for popup windows.
#if defined(FEAT_MOUSE) || defined(FEAT_TEXT_PROP) || defined(PROTO)
/*
* Compute the buffer line position from the screen position "rowp" / "colp" in
* window "win".
* "plines_cache" can be NULL (no cache) or an array with "win->w_height"
* entries that caches the plines_win() result from a previous call. Entry is
* zero if not computed yet. There must be no text or setting changes since
* the entry is put in the cache.
* Returns TRUE if the position is below the last line.
*/
int
mouse_comp_pos(
win_T *win,
int *rowp,
int *colp,
linenr_T *lnump,
int *plines_cache)
{
int col = *colp;
int row = *rowp;
linenr_T lnum;
int retval = FALSE;
int off;
int count;
#ifdef FEAT_RIGHTLEFT
if (win->w_p_rl)
col = win->w_width - 1 - col;
#endif
lnum = win->w_topline;
while (row > 0)
{
int cache_idx = lnum - win->w_topline;
if (plines_cache != NULL && plines_cache[cache_idx] > 0)
count = plines_cache[cache_idx];
else
{
#ifdef FEAT_DIFF
/* Don't include filler lines in "count" */
if (win->w_p_diff
# ifdef FEAT_FOLDING
&& !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL)
# endif
)
{
if (lnum == win->w_topline)
row -= win->w_topfill;
else
row -= diff_check_fill(win, lnum);
count = plines_win_nofill(win, lnum, TRUE);
}
else
#endif
count = plines_win(win, lnum, TRUE);
if (plines_cache != NULL)
plines_cache[cache_idx] = count;
}
if (count > row)
break; /* Position is in this buffer line. */
#ifdef FEAT_FOLDING
(void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL);
#endif
if (lnum == win->w_buffer->b_ml.ml_line_count)
{
retval = TRUE;
break; /* past end of file */
}
row -= count;
++lnum;
}
if (!retval)
{
/* Compute the column without wrapping. */
off = win_col_off(win) - win_col_off2(win);
if (col < off)
col = off;
col += row * (win->w_width - off);
/* add skip column (for long wrapping line) */
col += win->w_skipcol;
}
if (!win->w_p_wrap)
col += win->w_leftcol;
/* skip line number and fold column in front of the line */
col -= win_col_off(win);
if (col < 0)
{
#ifdef FEAT_NETBEANS_INTG
netbeans_gutter_click(lnum);
#endif
col = 0;
}
*colp = col;
*rowp = row;
*lnump = lnum;
return retval;
}
/*
* Find the window at screen position "*rowp" and "*colp". The positions are
* updated to become relative to the top-left of the window.
* When "popup" is FAIL_POPUP and the position is in a popup window then NULL
* is returned. When "popup" is IGNORE_POPUP then do not even check popup
* windows.
* Returns NULL when something is wrong.
*/
win_T *
mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
{
frame_T *fp;
win_T *wp;
#ifdef FEAT_TEXT_PROP
win_T *pwp = NULL;
if (popup != IGNORE_POPUP)
{
popup_reset_handled();
while ((wp = find_next_popup(TRUE)) != NULL)
{
if (*rowp >= wp->w_winrow && *rowp < wp->w_winrow + popup_height(wp)
&& *colp >= wp->w_wincol
&& *colp < wp->w_wincol + popup_width(wp))
pwp = wp;
}
if (pwp != NULL)
{
if (popup == FAIL_POPUP)
return NULL;
*rowp -= pwp->w_winrow;
*colp -= pwp->w_wincol;
return pwp;
}
}
#endif
fp = topframe;
*rowp -= firstwin->w_winrow;
for (;;)
{
if (fp->fr_layout == FR_LEAF)
break;
if (fp->fr_layout == FR_ROW)
{
for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
{
if (*colp < fp->fr_width)
break;
*colp -= fp->fr_width;
}
}
else /* fr_layout == FR_COL */
{
for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
{
if (*rowp < fp->fr_height)
break;
*rowp -= fp->fr_height;
}
}
}
/* When using a timer that closes a window the window might not actually
* exist. */
FOR_ALL_WINDOWS(wp)
if (wp == fp->fr_win)
{
#ifdef FEAT_MENU
*rowp -= wp->w_winbar_height;
#endif
return wp;
}
return NULL;
}
#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \
|| defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
|| defined(FEAT_GUI_PHOTON) || defined(FEAT_TERM_POPUP_MENU) \
|| defined(PROTO)
# define NEED_VCOL2COL
/*
* Translate window coordinates to buffer position without any side effects
*/
int
get_fpos_of_mouse(pos_T *mpos)
{
win_T *wp;
int row = mouse_row;
int col = mouse_col;
if (row < 0 || col < 0) /* check if it makes sense */
return IN_UNKNOWN;
/* find the window where the row is in */
wp = mouse_find_win(&row, &col, FAIL_POPUP);
if (wp == NULL)
return IN_UNKNOWN;
/*
* winpos and height may change in win_enter()!
*/
if (row >= wp->w_height) /* In (or below) status line */
return IN_STATUS_LINE;
if (col >= wp->w_width) /* In vertical separator line */
return IN_SEP_LINE;
if (wp != curwin)
return IN_UNKNOWN;
/* compute the position in the buffer line from the posn on the screen */
if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum, NULL))
return IN_STATUS_LINE; /* past bottom */
mpos->col = vcol2col(wp, mpos->lnum, col);
if (mpos->col > 0)
--mpos->col;
mpos->coladd = 0;
return IN_BUFFER;
}
#endif
#if defined(NEED_VCOL2COL) || defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) \
|| defined(PROTO)
/*
* Convert a virtual (screen) column to a character column.
* The first column is one.
*/
int
vcol2col(win_T *wp, linenr_T lnum, int vcol)
{
/* try to advance to the specified column */
int count = 0;
char_u *ptr;
char_u *line;
line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
while (count < vcol && *ptr != NUL)
{
count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
MB_PTR_ADV(ptr);
}
return (int)(ptr - line);
}
#endif
#endif /* FEAT_MOUSE */
#if defined(FEAT_GUI) || defined(MSWIN) || defined(PROTO)
/*
* Called when focus changed. Used for the GUI or for systems where this can