diff options
Diffstat (limited to 'server-client.c')
-rw-r--r-- | server-client.c | 212 |
1 files changed, 168 insertions, 44 deletions
diff --git a/server-client.c b/server-client.c index 5f1a58f1..591033ce 100644 --- a/server-client.c +++ b/server-client.c @@ -30,21 +30,22 @@ #include "tmux.h" -void server_client_free(int, short, void *); -void server_client_check_focus(struct window_pane *); -void server_client_check_resize(struct window_pane *); -key_code 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 *); -void server_client_set_title(struct client *); -void server_client_reset_state(struct client *); -int server_client_assume_paste(struct session *); - -void server_client_dispatch(struct imsg *, void *); -void server_client_dispatch_command(struct client *, struct imsg *); -void server_client_dispatch_identify(struct client *, struct imsg *); -void server_client_dispatch_shell(struct client *); +static void server_client_free(int, short, void *); +static void server_client_check_focus(struct window_pane *); +static void server_client_check_resize(struct window_pane *); +static key_code server_client_check_mouse(struct client *); +static void server_client_repeat_timer(int, short, void *); +static void server_client_click_timer(int, short, void *); +static void server_client_check_exit(struct client *); +static void server_client_check_redraw(struct client *); +static void server_client_set_title(struct client *); +static void server_client_reset_state(struct client *); +static int server_client_assume_paste(struct session *); + +static void server_client_dispatch(struct imsg *, void *); +static void server_client_dispatch_command(struct client *, struct imsg *); +static void server_client_dispatch_identify(struct client *, struct imsg *); +static void server_client_dispatch_shell(struct client *); /* Check if this client is inside this server. */ int @@ -95,6 +96,13 @@ server_client_get_key_table(struct client *c) return (name); } +/* Is this client using the default key table? */ +int +server_client_is_default_key_table(struct client *c) +{ + return (strcmp(c->keytable->name, server_client_get_key_table(c)) == 0); +} + /* Create a new client. */ void server_client_create(int fd) @@ -146,6 +154,7 @@ server_client_create(int fd) c->keytable->references++; evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); + evtimer_set(&c->click_timer, server_client_click_timer, c); TAILQ_INSERT_TAIL(&clients, c, entry); log_debug("new client %p", c); @@ -214,6 +223,7 @@ server_client_lost(struct client *c) free((void *)c->cwd); evtimer_del(&c->repeat_timer); + evtimer_del(&c->click_timer); key_bindings_unref_table(c->keytable); @@ -262,7 +272,7 @@ server_client_unref(struct client *c) } /* Free dead client. */ -void +static void server_client_free(__unused int fd, __unused short events, void *arg) { struct client *c = arg; @@ -287,17 +297,19 @@ server_client_detach(struct client *c, enum msgtype msgtype) } /* Check for mouse keys. */ -key_code +static key_code server_client_check_mouse(struct client *c) { - 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; - key_code key; + struct session *s = c->session; + struct mouse_event *m = &c->tty.mouse; + struct window *w; + struct window_pane *wp; + u_int x, y, b; + int flag; + key_code key; + struct timeval tv; + enum { NOTYPE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type = NOTYPE; + enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE; 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); @@ -321,10 +333,45 @@ server_client_check_mouse(struct client *c) x = m->x, y = m->y, b = m->lb; log_debug("up at %u,%u", x, y); } else { + if (c->flags & CLIENT_DOUBLECLICK) { + evtimer_del(&c->click_timer); + c->flags &= ~CLIENT_DOUBLECLICK; + if (m->b == c->click_button) { + type = DOUBLE; + x = m->x, y = m->y, b = m->b; + log_debug("double-click at %u,%u", x, y); + flag = CLIENT_TRIPLECLICK; + goto add_timer; + } + } else if (c->flags & CLIENT_TRIPLECLICK) { + evtimer_del(&c->click_timer); + c->flags &= ~CLIENT_TRIPLECLICK; + if (m->b == c->click_button) { + type = TRIPLE; + x = m->x, y = m->y, b = m->b; + log_debug("triple-click at %u,%u", x, y); + goto have_event; + } + } + type = DOWN; x = m->x, y = m->y, b = m->b; log_debug("down at %u,%u", x, y); + flag = CLIENT_DOUBLECLICK; + + add_timer: + if (KEYC_CLICK_TIMEOUT != 0) { + c->flags |= flag; + c->click_button = m->b; + + tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000; + tv.tv_usec = (KEYC_CLICK_TIMEOUT % 1000) * 1000L; + evtimer_del(&c->click_timer); + evtimer_add(&c->click_timer, &tv); + } } + +have_event: if (type == NOTYPE) return (KEYC_UNKNOWN); @@ -537,6 +584,62 @@ server_client_check_mouse(struct client *c) break; } break; + case DOUBLE: + switch (MOUSE_BUTTONS(b)) { + case 0: + if (where == PANE) + key = KEYC_DOUBLECLICK1_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK1_STATUS; + if (where == BORDER) + key = KEYC_DOUBLECLICK1_BORDER; + break; + case 1: + if (where == PANE) + key = KEYC_DOUBLECLICK2_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK2_STATUS; + if (where == BORDER) + key = KEYC_DOUBLECLICK2_BORDER; + break; + case 2: + if (where == PANE) + key = KEYC_DOUBLECLICK3_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK3_STATUS; + if (where == BORDER) + key = KEYC_DOUBLECLICK3_BORDER; + break; + } + break; + case TRIPLE: + switch (MOUSE_BUTTONS(b)) { + case 0: + if (where == PANE) + key = KEYC_TRIPLECLICK1_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK1_STATUS; + if (where == BORDER) + key = KEYC_TRIPLECLICK1_BORDER; + break; + case 1: + if (where == PANE) + key = KEYC_TRIPLECLICK2_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK2_STATUS; + if (where == BORDER) + key = KEYC_TRIPLECLICK2_BORDER; + break; + case 2: + if (where == PANE) + key = KEYC_TRIPLECLICK3_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK3_STATUS; + if (where == BORDER) + key = KEYC_TRIPLECLICK3_BORDER; + break; + } + break; } if (key == KEYC_UNKNOWN) return (KEYC_UNKNOWN); @@ -553,7 +656,7 @@ server_client_check_mouse(struct client *c) } /* Is this fast enough to probably be a paste? */ -int +static int server_client_assume_paste(struct session *s) { struct timeval tv; @@ -585,6 +688,7 @@ server_client_handle_key(struct client *c, key_code key) struct window *w; struct window_pane *wp; struct timeval tv; + const char *name; struct key_table *table; struct key_binding bd_find, *bd; int xtimeout; @@ -593,6 +697,10 @@ server_client_handle_key(struct client *c, key_code key) if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) return; w = s->curw->window; + if (KEYC_IS_MOUSE(key)) + wp = cmd_mouse_pane(m, NULL, NULL); + else + wp = w->active; /* Update the activity timer. */ if (gettimeofday(&c->activity_time, NULL) != 0) @@ -643,9 +751,21 @@ server_client_handle_key(struct client *c, key_code key) goto forward; retry: + /* + * Work out the current key table. If the pane is in a mode, use + * the mode table instead of the default key table. + */ + name = NULL; + if (wp != NULL && wp->mode != NULL && wp->mode->key_table != NULL) + name = wp->mode->key_table(wp); + if (name == NULL || !server_client_is_default_key_table(c)) + table = c->keytable; + else + table = key_bindings_get_table(name, 1); + /* Try to see if there is a key binding in the current table. */ bd_find.key = key; - bd = RB_FIND(key_bindings, &c->keytable->key_bindings, &bd_find); + bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); if (bd != NULL) { /* * Key was matched in this table. If currently repeating but a @@ -663,7 +783,6 @@ retry: * Take a reference to this table to make sure the key binding * doesn't disappear. */ - table = c->keytable; table->references++; /* @@ -702,7 +821,7 @@ retry: } /* If no match and we're not in the root table, that's it. */ - if (strcmp(c->keytable->name, server_client_get_key_table(c)) != 0) { + if (name == NULL && !server_client_is_default_key_table(c)) { server_client_set_key_table(c, NULL); server_status_client(c); return; @@ -722,10 +841,6 @@ retry: forward: if (c->flags & CLIENT_READONLY) return; - if (KEYC_IS_MOUSE(key)) - wp = cmd_mouse_pane(m, NULL, NULL); - else - wp = w->active; if (wp != NULL) window_pane_key(wp, c, s, key, m); } @@ -795,7 +910,7 @@ server_client_resize_event(__unused int fd, __unused short events, void *data) } /* Check if pane should be resized. */ -void +static void server_client_check_resize(struct window_pane *wp) { struct timeval tv = { .tv_usec = 250000 }; @@ -825,7 +940,7 @@ server_client_check_resize(struct window_pane *wp) } /* Check whether pane should be focused. */ -void +static void server_client_check_focus(struct window_pane *wp) { struct client *c; @@ -886,7 +1001,7 @@ focused: * tty_region/tty_reset/tty_update_mode already take care of not resetting * things that are already in their default state. */ -void +static void server_client_reset_state(struct client *c) { struct window *w = c->session->curw->window; @@ -922,7 +1037,7 @@ server_client_reset_state(struct client *c) } /* Repeat time callback. */ -void +static void server_client_repeat_timer(__unused int fd, __unused short events, void *data) { struct client *c = data; @@ -934,8 +1049,17 @@ server_client_repeat_timer(__unused int fd, __unused short events, void *data) } } +/* Double-click callback. */ +static void +server_client_click_timer(__unused int fd, __unused short events, void *data) +{ + struct client *c = data; + + c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK); +} + /* Check if client should be exited. */ -void +static void server_client_check_exit(struct client *c) { if (!(c->flags & CLIENT_EXIT)) @@ -953,7 +1077,7 @@ server_client_check_exit(struct client *c) } /* Check for client redraws. */ -void +static void server_client_check_redraw(struct client *c) { struct session *s = c->session; @@ -1009,7 +1133,7 @@ server_client_check_redraw(struct client *c) } /* Set client title. */ -void +static void server_client_set_title(struct client *c) { struct session *s = c->session; @@ -1034,7 +1158,7 @@ server_client_set_title(struct client *c) } /* Dispatch message from client. */ -void +static void server_client_dispatch(struct imsg *imsg, void *arg) { struct client *c = arg; @@ -1138,7 +1262,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) } /* Handle command message. */ -void +static void server_client_dispatch_command(struct client *c, struct imsg *imsg) { struct msg_command_data data; @@ -1191,7 +1315,7 @@ error: } /* Handle identify message. */ -void +static void server_client_dispatch_identify(struct client *c, struct imsg *imsg) { const char *data, *home; @@ -1303,7 +1427,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) } /* Handle shell message. */ -void +static void server_client_dispatch_shell(struct client *c) { const char *shell; |