summaryrefslogtreecommitdiffstats
path: root/server-client.c
diff options
context:
space:
mode:
authornicm <nicm>2015-04-19 21:34:21 +0000
committernicm <nicm>2015-04-19 21:34:21 +0000
commitbf635e7741f7b881f67ec7e4a5caa02f7ff3d786 (patch)
treec2da2accbb948824e54043a1539b2e3ca9187168 /server-client.c
parentee123c248951450100475717f5bd45f292d9bb4d (diff)
Rewrite of tmux mouse support which was a mess. Instead of having
options for "mouse-this" and "mouse-that", mouse events may be bound as keys and there is one option "mouse" that turns on mouse support entirely (set -g mouse on). See the new MOUSE SUPPORT section of the man page for description of the key names and new flags (-t= to specify the pane or window under mouse as a target, and send-keys -M to pass through a mouse event). The default builtin bindings for the mouse are: bind -n MouseDown1Pane select-pane -t=; send-keys -M bind -n MouseDown1Status select-window -t= bind -n MouseDrag1Pane copy-mode -M bind -n MouseDrag1Border resize-pane -M To get the effect of turning mode-mouse off, do: unbind -n MouseDrag1Pane unbind -temacs-copy MouseDrag1Pane The old mouse options are now gone, set-option -q may be used to suppress warnings if mixing configuration files.
Diffstat (limited to 'server-client.c')
-rw-r--r--server-client.c331
1 files changed, 244 insertions, 87 deletions
diff --git a/server-client.c b/server-client.c
index 352e8ab6..3968c50b 100644
--- a/server-client.c
+++ b/server-client.c
@@ -32,7 +32,7 @@
void server_client_check_focus(struct window_pane *);
void server_client_check_resize(struct window_pane *);
-void server_client_check_mouse(struct client *, struct window_pane *);
+int server_client_check_mouse(struct client *);
void server_client_repeat_timer(int, short, void *);
void server_client_check_exit(struct client *);
void server_client_check_redraw(struct client *);
@@ -91,13 +91,6 @@ server_client_create(int fd)
c->prompt_buffer = NULL;
c->prompt_index = 0;
- c->tty.mouse.xb = c->tty.mouse.button = 3;
- c->tty.mouse.x = c->tty.mouse.y = -1;
- c->tty.mouse.lx = c->tty.mouse.ly = -1;
- c->tty.mouse.sx = c->tty.mouse.sy = -1;
- c->tty.mouse.event = MOUSE_EVENT_UP;
- c->tty.mouse.flags = 0;
-
c->flags |= CLIENT_FOCUSED;
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
@@ -289,56 +282,228 @@ server_client_status_timer(void)
}
/* Check for mouse keys. */
-void
-server_client_check_mouse(struct client *c, struct window_pane *wp)
+int
+server_client_check_mouse(struct client *c)
{
- struct session *s = c->session;
- struct options *oo = &s->options;
- struct mouse_event *m = &c->tty.mouse;
- int statusat;
-
- statusat = status_at_line(c);
-
- /* Is this a window selection click on the status line? */
- if (statusat != -1 && m->y == (u_int)statusat &&
- options_get_number(oo, "mouse-select-window")) {
- if (m->event & MOUSE_EVENT_CLICK) {
- status_set_window_at(c, m->x);
- } else if (m->event == MOUSE_EVENT_WHEEL) {
- if (m->wheel == MOUSE_WHEEL_UP)
- session_previous(c->session, 0);
- else if (m->wheel == MOUSE_WHEEL_DOWN)
- session_next(c->session, 0);
- server_redraw_session(s);
+ struct session *s = c->session;
+ struct mouse_event *m = &c->tty.mouse;
+ struct window *w;
+ struct window_pane *wp;
+ enum { NOTYPE, DOWN, UP, DRAG, WHEEL } type = NOTYPE;
+ enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE;
+ u_int x, y, b;
+ int key;
+
+ log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y,
+ m->lx, m->ly, c->tty.mouse_drag_flag);
+
+ /* What type of event is this? */
+ if (MOUSE_DRAG(m->b)) {
+ type = DRAG;
+ if (c->tty.mouse_drag_flag) {
+ x = m->x, y = m->y, b = m->b;
+ log_debug("drag update at %u,%u", x, y);
+ } else {
+ x = m->lx, y = m->ly, b = m->lb;
+ log_debug("drag start at %u,%u", x, y);
}
- recalculate_sizes();
- return;
+ } else if (MOUSE_WHEEL(m->b)) {
+ type = WHEEL;
+ x = m->x, y = m->y, b = m->b;
+ log_debug("wheel at %u,%u", x, y);
+ } else if (MOUSE_BUTTONS(m->b) == 3) {
+ type = UP;
+ x = m->x, y = m->y, b = m->lb;
+ log_debug("up at %u,%u", x, y);
+ } else {
+ type = DOWN;
+ x = m->x, y = m->y, b = m->b;
+ log_debug("down at %u,%u", x, y);
}
+ if (type == NOTYPE)
+ return (KEYC_NONE);
- /*
- * Not on status line - adjust mouse position if status line is at the
- * top and limit if at the bottom. From here on a struct mouse
- * represents the offset onto the window itself.
- */
- if (statusat == 0 && m->y > 0)
- m->y--;
- else if (statusat > 0 && m->y >= (u_int)statusat)
- m->y = statusat - 1;
-
- /* Is this a pane selection? */
- if (options_get_number(oo, "mouse-select-pane") &&
- (m->event == MOUSE_EVENT_DOWN || m->event == MOUSE_EVENT_WHEEL)) {
- window_set_active_at(wp->window, m->x, m->y);
- server_redraw_window(wp->window);
- wp = wp->window->active; /* may have changed */
+ /* Always save the session. */
+ m->s = s->id;
+
+ /* Is this on the status line? */
+ m->statusat = status_at_line(c);
+ if (m->statusat != -1 && y == (u_int)m->statusat) {
+ w = status_get_window_at(c, x);
+ if (w == NULL)
+ return (KEYC_NONE);
+ m->w = w->id;
+ where = STATUS;
+ } else
+ m->w = -1;
+
+ /* Not on status line. Adjust position and check for border or pane. */
+ if (where == NOWHERE) {
+ if (m->statusat == 0 && y > 0)
+ y--;
+ else if (m->statusat > 0 && y >= (u_int)m->statusat)
+ y = m->statusat - 1;
+
+ TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
+ if ((wp->xoff + wp->sx == x &&
+ wp->yoff <= 1 + y &&
+ wp->yoff + wp->sy >= y) ||
+ (wp->yoff + wp->sy == y &&
+ wp->xoff <= 1 + x &&
+ wp->xoff + wp->sx >= x))
+ break;
+ }
+ if (wp != NULL)
+ where = BORDER;
+ else {
+ wp = window_get_active_at(s->curw->window, x, y);
+ if (wp != NULL)
+ where = PANE;
+ }
+ if (where == NOWHERE)
+ return (KEYC_NONE);
+ m->wp = wp->id;
+ m->w = wp->window->id;
+ } else
+ m->wp = -1;
+
+ /* Stop dragging if needed. */
+ if (type != DRAG && c->tty.mouse_drag_flag) {
+ if (c->tty.mouse_drag_release != NULL)
+ c->tty.mouse_drag_release(c, m);
+
+ c->tty.mouse_drag_update = NULL;
+ c->tty.mouse_drag_release = NULL;
+
+ c->tty.mouse_drag_flag = 0;
+ return (KEYC_NONE);
}
- /* Check if trying to resize pane. */
- if (options_get_number(oo, "mouse-resize-pane"))
- layout_resize_pane_mouse(c);
+ /* Convert to a key binding. */
+ key = KEYC_NONE;
+ switch (type) {
+ case NOTYPE:
+ break;
+ case DRAG:
+ if (c->tty.mouse_drag_update != NULL)
+ c->tty.mouse_drag_update(c, m);
+ else {
+ switch (MOUSE_BUTTONS(b)) {
+ case 0:
+ if (where == PANE)
+ key = KEYC_MOUSEDRAG1_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEDRAG1_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEDRAG1_BORDER;
+ break;
+ case 1:
+ if (where == PANE)
+ key = KEYC_MOUSEDRAG2_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEDRAG2_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEDRAG2_BORDER;
+ break;
+ case 2:
+ if (where == PANE)
+ key = KEYC_MOUSEDRAG3_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEDRAG3_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEDRAG3_BORDER;
+ break;
+ }
+ }
- /* Update last and pass through to client. */
- window_pane_mouse(wp, c->session, m);
+ c->tty.mouse_drag_flag = 1;
+ break;
+ case WHEEL:
+ if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) {
+ if (where == PANE)
+ key = KEYC_WHEELUP_PANE;
+ if (where == STATUS)
+ key = KEYC_WHEELUP_STATUS;
+ if (where == BORDER)
+ key = KEYC_WHEELUP_BORDER;
+ } else {
+ if (where == PANE)
+ key = KEYC_WHEELDOWN_PANE;
+ if (where == STATUS)
+ key = KEYC_WHEELDOWN_STATUS;
+ if (where == BORDER)
+ key = KEYC_WHEELDOWN_BORDER;
+ }
+ break;
+ case UP:
+ switch (MOUSE_BUTTONS(b)) {
+ case 0:
+ if (where == PANE)
+ key = KEYC_MOUSEUP1_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEUP1_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEUP1_BORDER;
+ break;
+ case 1:
+ if (where == PANE)
+ key = KEYC_MOUSEUP2_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEUP2_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEUP2_BORDER;
+ break;
+ case 2:
+ if (where == PANE)
+ key = KEYC_MOUSEUP3_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEUP3_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEUP3_BORDER;
+ break;
+ }
+ break;
+ case DOWN:
+ switch (MOUSE_BUTTONS(b)) {
+ case 0:
+ if (where == PANE)
+ key = KEYC_MOUSEDOWN1_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEDOWN1_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEDOWN1_BORDER;
+ break;
+ case 1:
+ if (where == PANE)
+ key = KEYC_MOUSEDOWN2_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEDOWN2_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEDOWN2_BORDER;
+ break;
+ case 2:
+ if (where == PANE)
+ key = KEYC_MOUSEDOWN3_PANE;
+ if (where == STATUS)
+ key = KEYC_MOUSEDOWN3_STATUS;
+ if (where == BORDER)
+ key = KEYC_MOUSEDOWN3_BORDER;
+ break;
+ }
+ break;
+ }
+ if (key == KEYC_NONE)
+ return (KEYC_NONE);
+
+ /* Apply modifiers if any. */
+ if (b & MOUSE_MASK_META)
+ key |= KEYC_ESCAPE;
+ if (b & MOUSE_MASK_CTRL)
+ key |= KEYC_CTRL;
+ if (b & MOUSE_MASK_SHIFT)
+ key |= KEYC_SHIFT;
+
+ return (key);
}
/* Is this fast enough to probably be a paste? */
@@ -361,6 +526,7 @@ server_client_assume_paste(struct session *s)
void
server_client_handle_key(struct client *c, int key)
{
+ struct mouse_event *m = &c->tty.mouse;
struct session *s;
struct window *w;
struct window_pane *wp;
@@ -372,21 +538,20 @@ server_client_handle_key(struct client *c, int key)
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
return;
+ /* No session, do nothing. */
if (c->session == NULL)
return;
s = c->session;
+ w = c->session->curw->window;
+ wp = w->active;
/* Update the activity timer. */
if (gettimeofday(&c->activity_time, NULL) != 0)
fatal("gettimeofday failed");
-
memcpy(&s->last_activity_time, &s->activity_time,
sizeof s->last_activity_time);
memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
- w = c->session->curw->window;
- wp = w->active;
-
/* Special case: number keys jump to pane in identify mode. */
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
if (c->flags & CLIENT_READONLY)
@@ -414,9 +579,19 @@ server_client_handle_key(struct client *c, int key)
if (key == KEYC_MOUSE) {
if (c->flags & CLIENT_READONLY)
return;
- server_client_check_mouse(c, wp);
- return;
- }
+ key = server_client_check_mouse(c);
+ if (key == KEYC_NONE)
+ return;
+
+ m->valid = 1;
+ m->key = key;
+
+ if (!options_get_number(&s->options, "mouse")) {
+ window_pane_key(wp, c, s, key, m);
+ return;
+ }
+ } else
+ m->valid = 0;
/* Is this a prefix key? */
if (key == options_get_number(&s->options, "prefix"))
@@ -442,9 +617,9 @@ server_client_handle_key(struct client *c, int key)
/* Try as a non-prefix key binding. */
if (ispaste || (bd = key_bindings_lookup(key)) == NULL) {
if (!(c->flags & CLIENT_READONLY))
- window_pane_key(wp, s, key);
+ window_pane_key(wp, c, s, key, m);
} else
- key_bindings_dispatch(bd, c);
+ key_bindings_dispatch(bd, c, m);
return;
}
@@ -458,7 +633,7 @@ server_client_handle_key(struct client *c, int key)
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
- window_pane_key(wp, s, key);
+ window_pane_key(wp, c, s, key, m);
}
return;
}
@@ -469,7 +644,7 @@ server_client_handle_key(struct client *c, int key)
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
- window_pane_key(wp, s, key);
+ window_pane_key(wp, c, s, key, m);
return;
}
@@ -485,7 +660,7 @@ server_client_handle_key(struct client *c, int key)
}
/* Dispatch the command. */
- key_bindings_dispatch(bd, c);
+ key_bindings_dispatch(bd, c, m);
}
/* Client functions that need to happen every loop. */
@@ -622,7 +797,6 @@ server_client_reset_state(struct client *c)
struct window_pane *wp = w->active;
struct screen *s = wp->screen;
struct options *oo = &c->session->options;
- struct options *wo = &w->options;
int status, mode, o;
if (c->flags & CLIENT_SUSPENDED)
@@ -642,29 +816,12 @@ server_client_reset_state(struct client *c)
}
/*
- * Resizing panes with the mouse requires at least button mode to give
- * a smooth appearance.
+ * Set mouse mode if requested. To support dragging, always use button
+ * mode.
*/
mode = s->mode;
- if ((c->tty.mouse.flags & MOUSE_RESIZE_PANE) &&
- !(mode & MODE_MOUSE_BUTTON))
- mode |= MODE_MOUSE_BUTTON;
-
- /*
- * Any mode will do for mouse-select-pane, but set standard mode if
- * none.
- */
- if ((mode & ALL_MOUSE_MODES) == 0) {
- if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
- options_get_number(oo, "mouse-select-pane"))
- mode |= MODE_MOUSE_STANDARD;
- else if (options_get_number(oo, "mouse-resize-pane"))
- mode |= MODE_MOUSE_STANDARD;
- else if (options_get_number(oo, "mouse-select-window"))
- mode |= MODE_MOUSE_STANDARD;
- else if (options_get_number(wo, "mode-mouse"))
- mode |= MODE_MOUSE_STANDARD;
- }
+ if (options_get_number(oo, "mouse"))
+ mode = (mode & ~ALL_MOUSE_MODES) | MODE_MOUSE_BUTTON;
/*
* Set UTF-8 mouse input if required. If the terminal is UTF-8, the
@@ -945,9 +1102,9 @@ server_client_msg_command(struct client *c, struct imsg *imsg)
cmd_free_argv(argc, argv);
if (c != cfg_client || cfg_finished)
- cmdq_run(c->cmdq, cmdlist);
+ cmdq_run(c->cmdq, cmdlist, NULL);
else
- cmdq_append(c->cmdq, cmdlist);
+ cmdq_append(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
return;