summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-03-11 19:30:45 +0100
committerBram Moolenaar <Bram@vim.org>2018-03-11 19:30:45 +0100
commitc48369c3fc507f398abbc933a60f653c6abe6701 (patch)
tree4c7f4a91eb8877c72c64ec0a615bfeac6064a50e
parente87303af3236b8fb5e1e3be4d0e2209344fbf8b2 (diff)
patch 8.0.1598: cannot select text in a terminal with the mousev8.0.1598
Problem: Cannot select text in a terminal with the mouse. Solution: When a job in a terminal is not consuming mouse events, use them for modeless selection. Also stop Insert mode when clicking in a terminal window.
-rw-r--r--src/libvterm/include/vterm.h14
-rw-r--r--src/libvterm/src/state.c8
-rw-r--r--src/libvterm/src/vterm_internal.h3
-rw-r--r--src/proto/terminal.pro1
-rw-r--r--src/terminal.c151
-rw-r--r--src/ui.c11
-rw-r--r--src/version.c2
7 files changed, 172 insertions, 18 deletions
diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h
index f731dcb8b7..df8e968777 100644
--- a/src/libvterm/include/vterm.h
+++ b/src/libvterm/include/vterm.h
@@ -259,6 +259,19 @@ typedef struct {
int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user);
} VTermStateCallbacks;
+typedef struct {
+ VTermPos pos;
+ int buttons;
+#define MOUSE_BUTTON_LEFT 0x01
+#define MOUSE_BUTTON_MIDDLE 0x02
+#define MOUSE_BUTTON_RIGHT 0x04
+ int flags;
+#define MOUSE_WANT_CLICK 0x01
+#define MOUSE_WANT_DRAG 0x02
+#define MOUSE_WANT_MOVE 0x04
+ /* useful to add protocol? */
+} VTermMouseState;
+
VTermState *vterm_obtain_state(VTerm *vt);
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);
@@ -272,6 +285,7 @@ void *vterm_state_get_unrecognised_fbdata(VTermState *state);
void vterm_state_reset(VTermState *state, int hard);
void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);
+void vterm_state_get_mousestate(const VTermState *state, VTermMouseState *mousestate);
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg);
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col);
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg);
diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c
index 05dbe5a964..9070e64a55 100644
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -1793,6 +1793,14 @@ void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos)
*cursorpos = state->pos;
}
+void vterm_state_get_mousestate(const VTermState *state, VTermMouseState *mousestate)
+{
+ mousestate->pos.col = state->mouse_col;
+ mousestate->pos.row = state->mouse_row;
+ mousestate->buttons = state->mouse_buttons;
+ mousestate->flags = state->mouse_flags;
+}
+
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user)
{
if(callbacks) {
diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h
index 3b337c0c19..3e7f1e5cb3 100644
--- a/src/libvterm/src/vterm_internal.h
+++ b/src/libvterm/src/vterm_internal.h
@@ -95,9 +95,6 @@ struct VTermState
int mouse_col, mouse_row;
int mouse_buttons;
int mouse_flags;
-#define MOUSE_WANT_CLICK 0x01
-#define MOUSE_WANT_DRAG 0x02
-#define MOUSE_WANT_MOVE 0x04
enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol;
diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro
index f7d06c050b..977537b716 100644
--- a/src/proto/terminal.pro
+++ b/src/proto/terminal.pro
@@ -12,6 +12,7 @@ void term_enter_job_mode(void);
int send_keys_to_term(term_T *term, int c, int typed);
int terminal_is_active(void);
cursorentry_T *term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg);
+void term_win_entered(void);
int term_use_loop(void);
int terminal_loop(int blocking);
void term_job_ended(job_T *job);
diff --git a/src/terminal.c b/src/terminal.c
index 7a80636ad0..43a2a317e2 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -38,8 +38,6 @@
* in tl_scrollback are no longer used.
*
* TODO:
- * - if the job in the terminal does not support the mouse, we can use the
- * mouse in the Terminal window for copy/paste and scrolling.
* - When using 'termguicolors' still use the 16 ANSI colors as-is. Helps for
* - In the GUI use a terminal emulator for :!cmd. Make the height the same as
* the window and position it higher up when it gets filled, so it looks like
@@ -900,6 +898,105 @@ term_send_mouse(VTerm *vterm, int button, int pressed)
return TRUE;
}
+static int enter_mouse_col = -1;
+static int enter_mouse_row = -1;
+
+/*
+ * Handle a mouse click, drag or release.
+ * Return TRUE when a mouse event is sent to the terminal.
+ */
+ static int
+term_mouse_click(VTerm *vterm, int key)
+{
+#if defined(FEAT_CLIPBOARD)
+ /* For modeless selection mouse drag and release events are ignored, unless
+ * they are preceded with a mouse down event */
+ static int ignore_drag_release = TRUE;
+ VTermMouseState mouse_state;
+
+ vterm_state_get_mousestate(vterm_obtain_state(vterm), &mouse_state);
+ if (mouse_state.flags == 0)
+ {
+ /* Terminal is not using the mouse, use modeless selection. */
+ switch (key)
+ {
+ case K_LEFTDRAG:
+ case K_LEFTRELEASE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE:
+ /* Ignore drag and release events when the button-down wasn't
+ * seen before. */
+ if (ignore_drag_release)
+ {
+ int save_mouse_col, save_mouse_row;
+
+ if (enter_mouse_col < 0)
+ break;
+
+ /* mouse click in the window gave us focus, handle that
+ * click now */
+ save_mouse_col = mouse_col;
+ save_mouse_row = mouse_row;
+ mouse_col = enter_mouse_col;
+ mouse_row = enter_mouse_row;
+ clip_modeless(MOUSE_LEFT, TRUE, FALSE);
+ mouse_col = save_mouse_col;
+ mouse_row = save_mouse_row;
+ }
+ /* FALLTHROUGH */
+ case K_LEFTMOUSE:
+ case K_RIGHTMOUSE:
+ if (key == K_LEFTRELEASE || key == K_RIGHTRELEASE)
+ ignore_drag_release = TRUE;
+ else
+ ignore_drag_release = FALSE;
+ /* Should we call mouse_has() here? */
+ if (clip_star.available)
+ {
+ int button, is_click, is_drag;
+
+ button = get_mouse_button(KEY2TERMCAP1(key),
+ &is_click, &is_drag);
+ if (mouse_model_popup() && button == MOUSE_LEFT
+ && (mod_mask & MOD_MASK_SHIFT))
+ {
+ /* Translate shift-left to right button. */
+ button = MOUSE_RIGHT;
+ mod_mask &= ~MOD_MASK_SHIFT;
+ }
+ clip_modeless(button, is_click, is_drag);
+ }
+ break;
+
+ case K_MIDDLEMOUSE:
+ if (clip_star.available)
+ insert_reg('*', TRUE);
+ break;
+ }
+ enter_mouse_col = -1;
+ return FALSE;
+ }
+#endif
+ enter_mouse_col = -1;
+
+ switch (key)
+ {
+ case K_LEFTMOUSE:
+ case K_LEFTMOUSE_NM: term_send_mouse(vterm, 1, 1); break;
+ case K_LEFTDRAG: term_send_mouse(vterm, 1, 1); break;
+ case K_LEFTRELEASE:
+ case K_LEFTRELEASE_NM: term_send_mouse(vterm, 1, 0); break;
+ case K_MOUSEMOVE: term_send_mouse(vterm, 0, 0); break;
+ case K_MIDDLEMOUSE: term_send_mouse(vterm, 2, 1); break;
+ case K_MIDDLEDRAG: term_send_mouse(vterm, 2, 1); break;
+ case K_MIDDLERELEASE: term_send_mouse(vterm, 2, 0); break;
+ case K_RIGHTMOUSE: term_send_mouse(vterm, 3, 1); break;
+ case K_RIGHTDRAG: term_send_mouse(vterm, 3, 1); break;
+ case K_RIGHTRELEASE: term_send_mouse(vterm, 3, 0); break;
+ }
+ return TRUE;
+}
+
/*
* Convert typed key "c" into bytes to send to the job.
* Return the number of bytes in "buf".
@@ -995,17 +1092,21 @@ term_convert_key(term_T *term, int c, char *buf)
case K_MOUSERIGHT: /* TODO */ return 0;
case K_LEFTMOUSE:
- case K_LEFTMOUSE_NM: other = term_send_mouse(vterm, 1, 1); break;
- case K_LEFTDRAG: other = term_send_mouse(vterm, 1, 1); break;
+ case K_LEFTMOUSE_NM:
+ case K_LEFTDRAG:
case K_LEFTRELEASE:
- case K_LEFTRELEASE_NM: other = term_send_mouse(vterm, 1, 0); break;
- case K_MOUSEMOVE: other = term_send_mouse(vterm, 0, 0); break;
- case K_MIDDLEMOUSE: other = term_send_mouse(vterm, 2, 1); break;
- case K_MIDDLEDRAG: other = term_send_mouse(vterm, 2, 1); break;
- case K_MIDDLERELEASE: other = term_send_mouse(vterm, 2, 0); break;
- case K_RIGHTMOUSE: other = term_send_mouse(vterm, 3, 1); break;
- case K_RIGHTDRAG: other = term_send_mouse(vterm, 3, 1); break;
- case K_RIGHTRELEASE: other = term_send_mouse(vterm, 3, 0); break;
+ case K_LEFTRELEASE_NM:
+ case K_MOUSEMOVE:
+ case K_MIDDLEMOUSE:
+ case K_MIDDLEDRAG:
+ case K_MIDDLERELEASE:
+ case K_RIGHTMOUSE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE: if (!term_mouse_click(vterm, c))
+ return 0;
+ other = TRUE;
+ break;
+
case K_X1MOUSE: /* TODO */ return 0;
case K_X1DRAG: /* TODO */ return 0;
case K_X1RELEASE: /* TODO */ return 0;
@@ -1473,6 +1574,8 @@ term_vgetc()
return c;
}
+static int mouse_was_outside = FALSE;
+
/*
* Send keys to terminal.
* Return FAIL when the key needs to be handled in Normal mode.
@@ -1483,7 +1586,6 @@ send_keys_to_term(term_T *term, int c, int typed)
{
char msg[KEY_BUF_LEN];
size_t len;
- static int mouse_was_outside = FALSE;
int dragging_outside = FALSE;
/* Catch keys that need to be handled as in Normal mode. */
@@ -1732,6 +1834,29 @@ prepare_restore_cursor_props(void)
}
/*
+ * Called when entering a window with the mouse. If this is a terminal window
+ * we may want to change state.
+ */
+ void
+term_win_entered()
+{
+ term_T *term = curbuf->b_term;
+
+ if (term != NULL)
+ {
+ if (term_use_loop())
+ {
+ reset_VIsual_and_resel();
+ if (State & INSERT)
+ stop_insert_mode = TRUE;
+ }
+ mouse_was_outside = FALSE;
+ enter_mouse_col = mouse_col;
+ enter_mouse_row = mouse_row;
+ }
+}
+
+/*
* Returns TRUE if the current window contains a terminal and we are sending
* keys to the job.
*/
diff --git a/src/ui.c b/src/ui.c
index 981f07f45a..87f3c1eb60 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -2827,11 +2827,18 @@ retnomove:
* (MOUSE_FOCUS was set above if we dragged first). */
if (dragwin == NULL || (flags & MOUSE_RELEASED))
win_enter(wp, TRUE); /* can make wp invalid! */
-#ifdef CHECK_DOUBLE_CLICK
- /* set topline, to be able to check for double click ourselves */
+
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 */
diff --git a/src/version.c b/src/version.c
index e30c251766..4c192717fc 100644
--- a/src/version.c
+++ b/src/version.c
@@ -767,6 +767,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1598,
+/**/
1597,
/**/
1596,