diff --git a/Makefile.am b/Makefile.am index 500672de..a956035e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -240,9 +240,19 @@ dist_tmux_SOURCES += image.c image-sixel.c endif if NEED_FUZZING -check_PROGRAMS = fuzz/input-fuzzer +check_PROGRAMS = \ + fuzz/input-fuzzer \ + fuzz/cmd-parse-fuzzer \ + fuzz/format-fuzzer \ + fuzz/style-fuzzer fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS) fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS) +fuzz_cmd_parse_fuzzer_LDFLAGS = $(FUZZING_LIBS) +fuzz_cmd_parse_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS) +fuzz_format_fuzzer_LDFLAGS = $(FUZZING_LIBS) +fuzz_format_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS) +fuzz_style_fuzzer_LDFLAGS = $(FUZZING_LIBS) +fuzz_style_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS) endif # Install tmux.1 in the right format. diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 4f2c9dd3..405c03c7 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -93,7 +93,7 @@ cmd_list_keys_get_table_width(struct key_binding **l, u_int n) } static struct key_binding ** -cmd_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit) +cmd_list_keys_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit) { const char *tables[] = { "prefix", "root" }; struct key_table *t; @@ -119,7 +119,7 @@ cmd_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit) } static void -cmd_filter_key_list(int filter_notes, int filter_key, key_code only, +cmd_list_keys_filter_key_list(int filter_notes, int filter_key, key_code only, struct key_binding **l, u_int *n) { key_code key; @@ -137,10 +137,10 @@ cmd_filter_key_list(int filter_notes, int filter_key, key_code only, } static void -cmd_format_add_key_binding(struct format_tree *ft, +cmd_list_keys_format_add_key_binding(struct format_tree *ft, const struct key_binding *bd, const char *prefix) { - const char *s; + char *s; if (bd->flags & KEY_BINDING_REPEAT) format_add(ft, "key_repeat", "1"); @@ -155,12 +155,12 @@ cmd_format_add_key_binding(struct format_tree *ft, format_add(ft, "key_prefix", "%s", prefix); format_add(ft, "key_table", "%s", bd->tablename); - s = key_string_lookup_key(bd->key, 0); - format_add(ft, "key_string", "%s", s); + format_add(ft, "key_string", "%s", key_string_lookup_key(bd->key, 0)); - s = cmd_list_print(bd->cmdlist, - CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS); + s = cmd_list_print(bd->cmdlist, CMD_LIST_PRINT_ESCAPED| + CMD_LIST_PRINT_NO_GROUPS); format_add(ft, "key_command", "%s", s); + free(s); } static enum cmd_retval @@ -213,14 +213,16 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) if (table) l = sort_get_key_bindings_table(table, &n, &sort_crit); else if (notes_only) - l = cmd_get_root_and_prefix(&n, &sort_crit); + l = cmd_list_keys_get_root_and_prefix(&n, &sort_crit); else l = sort_get_key_bindings(&n, &sort_crit); filter_notes = notes_only && !args_has(args, 'a'); filter_key = only != KEYC_UNKNOWN; - if (filter_notes || filter_key) - cmd_filter_key_list(filter_notes, filter_key, only, l, &n); + if (filter_notes || filter_key) { + cmd_list_keys_filter_key_list(filter_notes, filter_key, only, l, + &n); + } if (single) n = 1; @@ -232,7 +234,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) format_add(ft, "key_table_width", "%u", cmd_list_keys_get_table_width(l, n)); for (i = 0; i < n; i++) { - cmd_format_add_key_binding(ft, l[i], prefix); + cmd_list_keys_format_add_key_binding(ft, l[i], prefix); line = format_expand(ft, template); if ((single && tc != NULL) || n == 1) diff --git a/cmd.c b/cmd.c index 7e2e4fa1..72e02185 100644 --- a/cmd.c +++ b/cmd.c @@ -313,6 +313,8 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv) if (argc == 0) return (0); + if (argc < 0 || argc > 1000) + return (-1); *argv = xcalloc(argc, sizeof **argv); buf[len - 1] = '\0'; diff --git a/format-draw.c b/format-draw.c index c8cb74b6..510f28e0 100644 --- a/format-draw.c +++ b/format-draw.c @@ -49,6 +49,7 @@ format_is_type(struct format_range *fr, struct style *sy) case STYLE_RANGE_NONE: case STYLE_RANGE_LEFT: case STYLE_RANGE_RIGHT: + case STYLE_RANGE_CONTROL: return (1); case STYLE_RANGE_PANE: case STYLE_RANGE_WINDOW: @@ -1065,6 +1066,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, log_debug("%s: range user|%u at %u-%u", __func__, sr->argument, sr->start, sr->end); break; + case STYLE_RANGE_CONTROL: + log_debug("%s: range control|%u at %u-%u", __func__, + sr->argument, sr->start, sr->end); + break; } format_free_range(&frs, fr); } @@ -1116,7 +1121,7 @@ format_width(const char *expanded) /* * Trim on the left, taking #[] into account. Note, we copy the whole set of * unescaped #s, but only add their escaped size to width. This is because the - * format_draw function will actually do the escaping when it runs + * format_draw function will actually do the escaping. */ char * format_trim_left(const char *expanded, u_int limit) diff --git a/format.c b/format.c index 3cb4e34a..5b7ed129 100644 --- a/format.c +++ b/format.c @@ -84,6 +84,12 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) return (strcmp(fj1->cmd, fj2->cmd)); } +/* Maimum pad and trim width. */ +#define FORMAT_MAX_WIDTH 10000 + +/* Maimum repeat size. */ +#define FORMAT_MAX_REPEAT 10000 + /* Format modifiers. */ #define FORMAT_TIMESTRING 0x1 #define FORMAT_BASENAME 0x2 @@ -1009,7 +1015,7 @@ static void * format_cb_pane_flags(struct format_tree *ft) { if (ft->wp != NULL) - return (xstrdup(window_pane_printable_flags(ft->wp, 1))); + return (xstrdup(window_pane_printable_flags(ft->wp))); return (NULL); } @@ -1344,6 +1350,8 @@ format_cb_mouse_status_range(struct format_tree *ft) return (xstrdup("session")); case STYLE_RANGE_USER: return (xstrdup(sr->string)); + case STYLE_RANGE_CONTROL: + return (xstrdup("control")); } return (NULL); } @@ -1378,6 +1386,18 @@ format_cb_alternate_saved_y(struct format_tree *ft) return (NULL); } +/* Callback for bracket_paste_flag. */ +static void * +format_cb_bracket_paste_flag(struct format_tree *ft) +{ + if (ft->wp != NULL && ft->wp->screen != NULL) { + if (ft->wp->screen->mode & MODE_BRACKETPASTE) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + /* Callback for buffer_name. */ static void * format_cb_buffer_name(struct format_tree *ft) @@ -1616,9 +1636,13 @@ format_cb_client_user(struct format_tree *ft) struct passwd *pw; if (ft->c != NULL) { + if (ft->c->user != NULL) + return (xstrdup(ft->c->user)); uid = proc_get_peer_uid(ft->c->peer); - if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL) - return (xstrdup(pw->pw_name)); + if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL) { + ft->c->user = xstrdup(pw->pw_name); + return (xstrdup(ft->c->user)); + } } return (NULL); } @@ -2288,6 +2312,38 @@ format_cb_pane_pipe_pid(struct format_tree *ft) return (value); } +/* Callback for pane_pb_progress. */ +static void * +format_cb_pane_pb_progress(struct format_tree *ft) +{ + char *value = NULL; + + if (ft->wp != NULL) + xasprintf(&value, "%d", ft->wp->base.progress_bar.progress); + return (value); +} + +/* Callback for pane_pb_state. */ +static void * +format_cb_pane_pb_state(struct format_tree *ft) +{ + if (ft->wp != NULL) { + switch (ft->wp->base.progress_bar.state) { + case PROGRESS_BAR_HIDDEN: + return xstrdup("hidden"); + case PROGRESS_BAR_NORMAL: + return xstrdup("normal"); + case PROGRESS_BAR_ERROR: + return xstrdup("error"); + case PROGRESS_BAR_INDETERMINATE: + return xstrdup("indeterminate"); + case PROGRESS_BAR_PAUSED: + return xstrdup("paused"); + } + } + return (NULL); +} + /* Callback for pane_right. */ static void * format_cb_pane_right(struct format_tree *ft) @@ -3063,10 +3119,13 @@ format_cb_uid(__unused struct format_tree *ft) static void * format_cb_user(__unused struct format_tree *ft) { + static char *cached; struct passwd *pw; - if ((pw = getpwuid(getuid())) != NULL) - return (xstrdup(pw->pw_name)); + if (cached == NULL && (pw = getpwuid(getuid())) != NULL) + cached = xstrdup(pw->pw_name); + if (cached != NULL) + return (xstrdup(cached)); return (NULL); } @@ -3101,6 +3160,9 @@ static const struct format_table_entry format_table[] = { { "alternate_saved_y", FORMAT_TABLE_STRING, format_cb_alternate_saved_y }, + { "bracket_paste_flag", FORMAT_TABLE_STRING, + format_cb_bracket_paste_flag + }, { "buffer_created", FORMAT_TABLE_TIME, format_cb_buffer_created }, @@ -3395,6 +3457,12 @@ static const struct format_table_entry format_table[] = { { "pane_path", FORMAT_TABLE_STRING, format_cb_pane_path }, + { "pane_pb_progress", FORMAT_TABLE_STRING, + format_cb_pane_pb_progress + }, + { "pane_pb_state", FORMAT_TABLE_STRING, + format_cb_pane_pb_state + }, { "pane_pid", FORMAT_TABLE_STRING, format_cb_pane_pid }, @@ -4256,6 +4324,8 @@ format_build_modifiers(struct format_expand_state *es, const char **s, /* Skip any separator character. */ if (*cp == ';') cp++; + if (*cp == '\0') + break; /* Check single character modifiers with no arguments. */ if (strchr("labcdnwETSWPL!<>", cp[0]) != NULL && @@ -4816,7 +4886,7 @@ format_replace_expression(struct format_modifier *mexp, /* The third argument may be precision. */ if (argc >= 3) { - prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr); + prec = strtonum(mexp->argv[2], INT_MIN + 1, INT_MAX, &errstr); if (errstr != NULL) { format_log(es, "expression precision %s: %s", errstr, mexp->argv[2]); @@ -4961,8 +5031,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, case '=': if (fm->argc < 1) break; - limit = strtonum(fm->argv[0], INT_MIN, INT_MAX, - &errstr); + limit = strtonum(fm->argv[0], -FORMAT_MAX_WIDTH, + FORMAT_MAX_WIDTH, &errstr); if (errstr != NULL) limit = 0; if (fm->argc >= 2 && fm->argv[1] != NULL) @@ -4971,8 +5041,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, case 'p': if (fm->argc < 1) break; - width = strtonum(fm->argv[0], INT_MIN, INT_MAX, - &errstr); + width = strtonum(fm->argv[0], -FORMAT_MAX_WIDTH, + FORMAT_MAX_WIDTH, &errstr); if (errstr != NULL) width = 0; break; @@ -5195,7 +5265,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, format_log(es, "repeat syntax error: %s", copy); goto fail; } - nrep = strtonum(right, 1, 10000, &errstr); + nrep = strtonum(right, 1, FORMAT_MAX_REPEAT, &errstr); if (errstr != NULL) value = xstrdup(""); else { @@ -5390,6 +5460,7 @@ done: if (marker != NULL && strcmp(new, value) != 0) { free(value); xasprintf(&value, "%s%s", new, marker); + free(new); } else { free(value); value = new; @@ -5400,6 +5471,7 @@ done: if (marker != NULL && strcmp(new, value) != 0) { free(value); xasprintf(&value, "%s%s", marker, new); + free(new); } else { free(value); value = new; @@ -5512,7 +5584,7 @@ format_expand1(struct format_expand_state *es, const char *fmt) buf[off++] = *fmt++; continue; } - if (*fmt++ == '\0') + if (*++fmt == '\0') break; ch = (u_char)*fmt++; diff --git a/fuzz/cmd-parse-fuzzer.c b/fuzz/cmd-parse-fuzzer.c new file mode 100644 index 00000000..2e135422 --- /dev/null +++ b/fuzz/cmd-parse-fuzzer.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026 David Korczynski + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Fuzz the tmux command parser (cmd_parse_from_buffer). + * + * This exercises: + * - cmd-parse.y (yacc grammar, lexer, command building) + * - cmd.c (command lookup and validation) + * - arguments.c (argument parsing and flag handling) + * - cmd-find.c (target resolution) + * - options.c (option name lookups during parsing) + */ + +#include +#include + +#include "tmux.h" + +struct event_base *libevent; + +int +LLVMFuzzerTestOneInput(const u_char *data, size_t size) +{ + struct cmd_parse_input pi; + struct cmd_parse_result *pr; + + if (size > 2048 || size == 0) + return 0; + + memset(&pi, 0, sizeof pi); + pi.flags = CMD_PARSE_QUIET; + + pr = cmd_parse_from_buffer(data, size, &pi); + switch (pr->status) { + case CMD_PARSE_SUCCESS: + cmd_list_free(pr->cmdlist); + break; + case CMD_PARSE_ERROR: + free(pr->error); + break; + default: + break; + } + + return 0; +} + +int +LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv) +{ + const struct options_table_entry *oe; + + global_environ = environ_create(); + global_options = options_create(NULL); + global_s_options = options_create(NULL); + global_w_options = options_create(NULL); + for (oe = options_table; oe->name != NULL; oe++) { + if (oe->scope & OPTIONS_TABLE_SERVER) + options_default(global_options, oe); + if (oe->scope & OPTIONS_TABLE_SESSION) + options_default(global_s_options, oe); + if (oe->scope & OPTIONS_TABLE_WINDOW) + options_default(global_w_options, oe); + } + libevent = osdep_event_init(); + socket_path = xstrdup("dummy"); + + return 0; +} diff --git a/fuzz/cmd-parse-fuzzer.dict b/fuzz/cmd-parse-fuzzer.dict new file mode 100644 index 00000000..cbd933f9 --- /dev/null +++ b/fuzz/cmd-parse-fuzzer.dict @@ -0,0 +1,133 @@ +# tmux command names +"set-option" +"bind-key" +"unbind-key" +"send-keys" +"new-session" +"new-window" +"split-window" +"select-window" +"select-pane" +"kill-pane" +"kill-window" +"kill-session" +"kill-server" +"list-sessions" +"list-windows" +"list-panes" +"list-keys" +"list-buffers" +"list-clients" +"list-commands" +"attach-session" +"detach-client" +"switch-client" +"rename-session" +"rename-window" +"resize-pane" +"resize-window" +"display-message" +"display-menu" +"display-popup" +"display-panes" +"copy-mode" +"paste-buffer" +"capture-pane" +"save-buffer" +"load-buffer" +"set-buffer" +"delete-buffer" +"show-buffer" +"choose-buffer" +"choose-tree" +"choose-client" +"if-shell" +"run-shell" +"source-file" +"command-prompt" +"confirm-before" +"pipe-pane" +"wait-for" +"set-environment" +"show-environment" +"set-hook" +"show-hooks" +"show-messages" +"show-options" +"set-window-option" +"show-window-options" +"clear-history" +"clock-mode" +"find-window" +"join-pane" +"move-pane" +"break-pane" +"swap-pane" +"swap-window" +"move-window" +"link-window" +"unlink-window" +"rotate-window" +"next-window" +"previous-window" +"last-window" +"last-pane" +"next-layout" +"previous-layout" +"select-layout" +"customize-mode" +"refresh-client" +"suspend-client" +"lock-client" +"lock-server" +"lock-session" +"respawn-pane" +"respawn-window" +"start-server" +"server-access" +"send-prefix" +"clear-prompt-history" +"show-prompt-history" + +# Common flags and syntax +"-t" +"-s" +"-g" +"-w" +"-p" +"-a" +"-o" +"-q" +"-u" +"-F" +"-f" +"-b" +"-d" +"-e" +"-n" +"-r" + +# Targets and option names +"status" +"default" +"mouse" +"on" +"off" +"vi" +"emacs" +"set -g" +"set -s" +"setw" +"bind" +"unbind" + +# Syntax elements +"{" +"}" +";" +"#{" +"%if" +"%elif" +"%else" +"%endif" +"%hidden" diff --git a/fuzz/cmd-parse-fuzzer.options b/fuzz/cmd-parse-fuzzer.options new file mode 100644 index 00000000..60bd9b0b --- /dev/null +++ b/fuzz/cmd-parse-fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 2048 diff --git a/fuzz/format-fuzzer.c b/fuzz/format-fuzzer.c new file mode 100644 index 00000000..d447c506 --- /dev/null +++ b/fuzz/format-fuzzer.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2026 David Korczynski + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Fuzz the tmux format string expander (format_expand). + * + * This exercises: + * - format.c (format parsing, modifier chains, conditionals, math, regex) + * - colour.c (colour name and RGB parsing within formats) + * - utf8.c (UTF-8 width calculations in format padding) + */ + +#include +#include + +#include "tmux.h" + +struct event_base *libevent; + +int +LLVMFuzzerTestOneInput(const u_char *data, size_t size) +{ + struct format_tree *ft; + char *buf, *expanded; + + if (size > 2048 || size == 0) + return 0; + + /* Null-terminate the input for format_expand. */ + buf = malloc(size + 1); + if (buf == NULL) + return 0; + memcpy(buf, data, size); + buf[size] = '\0'; + + ft = format_create(NULL, NULL, 0, FORMAT_NOJOBS); + format_add(ft, "session_name", "%s", "fuzz-session"); + format_add(ft, "window_index", "%d", 0); + format_add(ft, "window_name", "%s", "fuzz-window"); + format_add(ft, "pane_index", "%d", 0); + format_add(ft, "pane_id", "%s", "%%0"); + format_add(ft, "host", "%s", "fuzzhost"); + format_add(ft, "pane_width", "%d", 80); + format_add(ft, "pane_height", "%d", 25); + + expanded = format_expand(ft, buf); + free(expanded); + format_free(ft); + + free(buf); + return 0; +} + +int +LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv) +{ + const struct options_table_entry *oe; + + global_environ = environ_create(); + global_options = options_create(NULL); + global_s_options = options_create(NULL); + global_w_options = options_create(NULL); + for (oe = options_table; oe->name != NULL; oe++) { + if (oe->scope & OPTIONS_TABLE_SERVER) + options_default(global_options, oe); + if (oe->scope & OPTIONS_TABLE_SESSION) + options_default(global_s_options, oe); + if (oe->scope & OPTIONS_TABLE_WINDOW) + options_default(global_w_options, oe); + } + libevent = osdep_event_init(); + socket_path = xstrdup("dummy"); + + return 0; +} diff --git a/fuzz/format-fuzzer.dict b/fuzz/format-fuzzer.dict new file mode 100644 index 00000000..fb79cf9a --- /dev/null +++ b/fuzz/format-fuzzer.dict @@ -0,0 +1,71 @@ +# Format expansion syntax +"#{" +"}" +"#{?" +"#{==" +"#{!=" +"#{<" +"#{>" +"#{m:" +"#{C:" +"#{s/" +"#{t:" +"#{T:" +"#{E:" +"#{S:" +"#{W:" +"#{P:" +"##" + +# Common format modifiers +"b:" +"d:" +"q:" +"l:" +"e:" +"t:" +"p:" +"w:" +"n:" +"a:" +"=:" +"||" +"&&" +"," +"#{e|" +"#{p-1:" +"#{=/10/...:" + +# Format variables +"session_name" +"window_index" +"window_name" +"pane_index" +"pane_id" +"host" +"pane_width" +"pane_height" +"pane_current_command" +"pane_pid" +"session_id" +"window_id" +"client_name" +"version" +"line" + +# Conditionals +"#{?pane_active," +",}" +"#{?#{==:" + +# Math and comparison +"#{e|+:" +"#{e|-:" +"#{e|*:" +"#{e|/:" +"#{e|%:" + +# Nested +"#{=" +"#{" +"#{l:" diff --git a/fuzz/format-fuzzer.options b/fuzz/format-fuzzer.options new file mode 100644 index 00000000..60bd9b0b --- /dev/null +++ b/fuzz/format-fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 2048 diff --git a/fuzz/style-fuzzer.c b/fuzz/style-fuzzer.c new file mode 100644 index 00000000..f9d40e61 --- /dev/null +++ b/fuzz/style-fuzzer.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026 David Korczynski + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Fuzz the tmux style parser (style_parse). + * + * This exercises: + * - style.c (style string parsing, alignment, ranges) + * - colour.c (colour name, RGB, and indexed colour parsing) + */ + +#include +#include + +#include "tmux.h" + +struct event_base *libevent; + +int +LLVMFuzzerTestOneInput(const u_char *data, size_t size) +{ + struct style sy; + struct grid_cell gc; + char *buf; + + if (size > 512 || size == 0) + return 0; + + /* Null-terminate the input for style_parse. */ + buf = malloc(size + 1); + if (buf == NULL) + return 0; + memcpy(buf, data, size); + buf[size] = '\0'; + + memset(&gc, 0, sizeof gc); + style_set(&sy, &gc); + + style_parse(&sy, &gc, buf); + + free(buf); + return 0; +} + +int +LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv) +{ + const struct options_table_entry *oe; + + global_environ = environ_create(); + global_options = options_create(NULL); + global_s_options = options_create(NULL); + global_w_options = options_create(NULL); + for (oe = options_table; oe->name != NULL; oe++) { + if (oe->scope & OPTIONS_TABLE_SERVER) + options_default(global_options, oe); + if (oe->scope & OPTIONS_TABLE_SESSION) + options_default(global_s_options, oe); + if (oe->scope & OPTIONS_TABLE_WINDOW) + options_default(global_w_options, oe); + } + libevent = osdep_event_init(); + socket_path = xstrdup("dummy"); + + return 0; +} diff --git a/fuzz/style-fuzzer.dict b/fuzz/style-fuzzer.dict new file mode 100644 index 00000000..2834734c --- /dev/null +++ b/fuzz/style-fuzzer.dict @@ -0,0 +1,73 @@ +# Style attributes +"default" +"ignore" +"nodefaults" +"bright" +"bold" +"dim" +"underscore" +"blink" +"reverse" +"hidden" +"italics" +"overline" +"strikethrough" +"double-underscore" +"curly-underscore" +"dotted-underscore" +"dashed-underscore" +"nobright" +"nobold" +"nodim" +"nounderscore" +"noblink" +"noreverse" +"nohidden" +"noitalics" +"nooverline" +"nostrikethrough" + +# Colours +"fg=" +"bg=" +"us=" +"fill=" +"colour0" +"colour255" +"red" +"green" +"blue" +"yellow" +"cyan" +"magenta" +"white" +"black" + +# RGB and hex +"#ff0000" +"#00ff00" +"#0000ff" + +# Alignment and ranges +"align=left" +"align=centre" +"align=right" +"align=absolute-centre" +"list=on" +"list=focus" +"list=left-marker" +"list=right-marker" +"range=left" +"range=right" +"range=pane" +"range=window" +"range=session" +"range=user" + +# Width and padding +"width=" +"pad=" + +# Delimiters +"," +" " diff --git a/fuzz/style-fuzzer.options b/fuzz/style-fuzzer.options new file mode 100644 index 00000000..5d468bc6 --- /dev/null +++ b/fuzz/style-fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 512 diff --git a/grid.c b/grid.c index d5d2b37f..0d1db844 100644 --- a/grid.c +++ b/grid.c @@ -200,7 +200,7 @@ grid_adjust_lines(struct grid *gd, u_int lines) /* Copy default into a cell. */ static void -grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg) +grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg, int moved) { struct grid_line *gl = &gd->linedata[py]; struct grid_cell_entry *gce = &gl->celldata[px]; @@ -209,7 +209,7 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg) int had_extd = (gce->flags & GRID_FLAG_EXTENDED); memcpy(gce, &grid_cleared_entry, sizeof *gce); - if (had_extd && old_offset < gl->extdsize) { + if (!moved && had_extd && old_offset < gl->extdsize) { gce->flags |= GRID_FLAG_EXTENDED; gce->offset = old_offset; gee = grid_extended_cell(gl, gce, &grid_cleared_cell); @@ -515,7 +515,7 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg) (sx - gl->cellsize) * sizeof *gl->celldata); } for (xx = gl->cellsize; xx < sx; xx++) - grid_clear_cell(gd, xx, py, bg); + grid_clear_cell(gd, xx, py, bg, 0); gl->cellsize = sx; } @@ -683,7 +683,7 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg) grid_expand_line(gd, yy, px + ox, 8); /* default bg first */ for (xx = px; xx < px + ox; xx++) - grid_clear_cell(gd, xx, yy, bg); + grid_clear_cell(gd, xx, yy, bg, 0); } } @@ -777,7 +777,7 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx, for (xx = px; xx < px + nx; xx++) { if (xx >= dx && xx < dx + nx) continue; - grid_clear_cell(gd, xx, py, bg); + grid_clear_cell(gd, xx, py, bg, 1); } } diff --git a/image-sixel.c b/image-sixel.c index f6eaade3..c37e2cce 100644 --- a/image-sixel.c +++ b/image-sixel.c @@ -487,9 +487,9 @@ static void sixel_print_add(char **buf, size_t *len, size_t *used, const char *s, size_t slen) { - if (*used + slen >= *len + 1) { + while (*used + slen >= *len + 1) { + *buf = xreallocarray(*buf, 2, *len); (*len) *= 2; - *buf = xrealloc(*buf, *len); } memcpy(*buf + *used, s, slen); (*used) += slen; diff --git a/input-keys.c b/input-keys.c index eb5dae88..fdce5409 100644 --- a/input-keys.c +++ b/input-keys.c @@ -673,8 +673,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) } /* Ignore internal function key codes. */ - if ((key >= KEYC_BASE && key < KEYC_BASE_END) || - (key >= KEYC_USER && key < KEYC_USER_END)) { + if (KEYC_IS_USER(key) || KEYC_IS_SPECIAL(key) || KEYC_IS_MOUSE(key)) { log_debug("%s: ignoring key 0x%llx", __func__, key); return (0); } diff --git a/input.c b/input.c index 707328dc..671f5788 100644 --- a/input.c +++ b/input.c @@ -164,6 +164,7 @@ static void input_reset_cell(struct input_ctx *); static void input_report_current_theme(struct input_ctx *); static void input_osc_4(struct input_ctx *, const char *); static void input_osc_8(struct input_ctx *, const char *); +static void input_osc_9(struct input_ctx *, const char *); static void input_osc_10(struct input_ctx *, const char *); static void input_osc_11(struct input_ctx *, const char *); static void input_osc_12(struct input_ctx *, const char *); @@ -2673,6 +2674,9 @@ input_exit_osc(struct input_ctx *ictx) case 8: input_osc_8(ictx, p); break; + case 9: + input_osc_9(ictx, p); + break; case 10: input_osc_10(ictx, p); break; @@ -2941,6 +2945,57 @@ bad: free(id); } +/* Helper to handle setting the progress bar and redrawing. */ +static void +input_set_progress_bar(struct input_ctx *ictx, enum progress_bar_state state, + int p) +{ + screen_set_progress_bar(ictx->ctx.s, state, p); + if (ictx->wp != NULL) { + server_redraw_window_borders(ictx->wp->window); + server_status_window(ictx->wp->window); + } +} + +/* Handle the OSC 9;4 sequence for progress bars. */ +static void +input_osc_9(struct input_ctx *ictx, const char *p) +{ + const char *pb = p; + enum progress_bar_state state; + int progress = 0; + + if (*pb++ != '4') + return; + if (*pb == '\0' || (*pb == ';' && pb[1] == '\0')) + return; + + if (*pb++ != ';') + return; + if (*pb < '0' || *pb > '4') + goto bad; + state = *pb++ - '0'; + + if (*pb == '\0' || (*pb == ';' && pb[1] == '\0')) { + input_set_progress_bar(ictx, state, -1); + return; + } + + if (*pb++ != ';') + goto bad; + while (*pb >= '0' && *pb <= '9') { + if (progress > 100) + goto bad; + progress = progress * 10 + *pb++ - '0'; + } + if (*pb != '\0' || progress < 0 || progress > 100) + goto bad; + input_set_progress_bar(ictx, state, progress); + return; + +bad: + log_debug("bad OSC 9;4 %s", p); +} /* Handle the OSC 10 sequence for setting and querying foreground colour. */ static void @@ -3151,7 +3206,7 @@ input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out, return (0); } - len = (strlen(end) / 4) * 3; + len = ((strlen(end) + 3) / 4) * 3; if (len == 0) return (0); diff --git a/key-string.c b/key-string.c index 8b9b5604..3df9da4b 100644 --- a/key-string.c +++ b/key-string.c @@ -202,7 +202,7 @@ key_string_search_table(const char *string) return (key_string_table[i].key); } - if (sscanf(string, "User%u", &user) == 1 && user < KEYC_NUSER) + if (sscanf(string, "User%u", &user) == 1 && user <= KEYC_NUSER) return (KEYC_USER + user); return (KEYC_UNKNOWN); @@ -418,7 +418,7 @@ key_string_lookup_key(key_code key, int with_flags) s = "MouseMoveBorder"; goto append; } - if (key >= KEYC_USER && key < KEYC_USER_END) { + if (KEYC_IS_USER(key)) { snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER)); strlcat(out, tmp, sizeof out); goto out; diff --git a/options-table.c b/options-table.c index 4125275c..34bffcdd 100644 --- a/options-table.c +++ b/options-table.c @@ -91,7 +91,7 @@ static const char *options_table_window_size_list[] = { "largest", "smallest", "manual", "latest", NULL }; static const char *options_table_remain_on_exit_list[] = { - "off", "on", "failed", "keypress", NULL + "off", "on", "failed", "key", NULL }; static const char *options_table_destroy_unattached_list[] = { "off", "on", "keep-last", "keep-group", NULL @@ -1429,8 +1429,9 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .choices = options_table_remain_on_exit_list, .default_num = 0, - .text = "Whether panes should remain ('on') or be automatically " - "killed ('off' or 'failed') when the program inside exits." + .text = "Whether panes should remain ('on'), remain until a key is " + "pressed ('key') or be automatically killed ('off' or " + "'failed') when the program inside exits." }, { .name = "remain-on-exit-format", diff --git a/regsub.c b/regsub.c index 61a9c324..a863f9fd 100644 --- a/regsub.c +++ b/regsub.c @@ -41,7 +41,7 @@ regsub_expand(char **buf, ssize_t *len, const char *with, const char *text, u_int i; for (cp = with; *cp != '\0'; cp++) { - if (*cp == '\\') { + if (cp[0] == '\\' && cp[1] != '\0') { cp++; if (*cp >= '0' && *cp <= '9') { i = *cp - '0'; @@ -68,6 +68,8 @@ regsub(const char *pattern, const char *with, const char *text, int flags) if (*text == '\0') return (xstrdup("")); + if (*pattern == '\0') + return (xstrdup(text)); if (regcomp(&r, pattern, flags) != 0) return (NULL); diff --git a/screen-redraw.c b/screen-redraw.c index 07171b7d..066bc94f 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -602,6 +602,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, struct grid_cell gc; const char *fmt, *border_opt; struct format_tree *ft; + struct style_line_entry *sle = &wp->border_status_line; char *expanded; int pane_status = rctx->pane_status, sb_w = 0; int pane_scrollbars = rctx->pane_scrollbars; @@ -660,12 +661,15 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, gc.attr &= ~GRID_ATTR_CHARSET; screen_write_cursormove(&ctx, 0, 0, 0); - format_draw(&ctx, &gc, width, expanded, NULL, 0); - screen_write_stop(&ctx); + style_ranges_free(&sle->ranges); + format_draw(&ctx, &gc, width, expanded, &sle->ranges, 0); - free(expanded); + screen_write_stop(&ctx); format_free(ft); + free(sle->expanded); + sle->expanded = expanded; + if (grid_compare(wp->status_screen.grid, old.grid) == 0) { screen_free(&old); return (0); diff --git a/screen.c b/screen.c index a07a8e8c..63c6009c 100644 --- a/screen.c +++ b/screen.c @@ -131,6 +131,7 @@ screen_reinit(struct screen *s) image_free_all(s); #endif + screen_set_progress_bar(s, PROGRESS_BAR_HIDDEN, 0); screen_reset_hyperlinks(s); } @@ -296,6 +297,19 @@ screen_pop_title(struct screen *s) } } +/* + * Set the progress bar state and progress. The progress will not be updated + * if p is negative. + */ +void +screen_set_progress_bar(struct screen *s, enum progress_bar_state pbs, int p) +{ + s->progress_bar.state = pbs; + if (p >= 0 && pbs != PROGRESS_BAR_INDETERMINATE) + s->progress_bar.progress = p; +} + + /* Resize screen with options. */ void screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow, @@ -772,8 +786,9 @@ screen_mode_to_string(int mode) return (tmp); } +/* Convert screen to a string. */ const char * -screen_print(struct screen *s) +screen_print(struct screen *s, int line) { static char *buf; static size_t len = 16384; @@ -789,6 +804,8 @@ screen_print(struct screen *s) buf = xmalloc(len); for (y = 0; y < screen_hsize(s) + s->grid->sy; y++) { + if (line >= 0 && y != (u_int)line) + continue; n = snprintf(buf + last, len - last, "%.4d \"", y); if (n <= 0 || (u_int)n >= len - last) goto out; diff --git a/server-client.c b/server-client.c index 4d11c2cc..83dfbcef 100644 --- a/server-client.c +++ b/server-client.c @@ -29,19 +29,6 @@ #include "tmux.h" -enum mouse_where { - NOWHERE, - PANE, - STATUS, - STATUS_LEFT, - STATUS_RIGHT, - STATUS_DEFAULT, - BORDER, - SCROLLBAR_UP, - SCROLLBAR_SLIDER, - SCROLLBAR_DOWN -}; - static void server_client_free(int, short, void *); static void server_client_check_pane_resize(struct window_pane *); static void server_client_check_pane_buffer(struct window_pane *); @@ -546,6 +533,7 @@ server_client_free(__unused int fd, __unused short events, void *arg) if (c->references == 0) { free((void *)c->name); + free((void *)c->user); free(c); } } @@ -609,7 +597,7 @@ server_client_exec(struct client *c, const char *cmd) free(msg); } -static enum mouse_where +static enum key_code_mouse_location server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, u_int *sl_mpos) { @@ -641,46 +629,50 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, /* Check if point is within the pane or scrollbar. */ if (((pane_status != PANE_STATUS_OFF && - (int)py != pane_status_line && (int)py != wp->yoff + (int)wp->sy) || + (int)py != pane_status_line && (int)py != wp->yoff + (int)wp->sy) || (wp->yoff == 0 && py < wp->sy) || ((int)py >= wp->yoff && (int)py < wp->yoff + (int)wp->sy)) && ((sb_pos == PANE_SCROLLBARS_RIGHT && - (int)px < wp->xoff + (int)wp->sx + sb_pad + sb_w) || + (int)px < (int)wp->xoff + (int)wp->sx + sb_pad + sb_w) || (sb_pos == PANE_SCROLLBARS_LEFT && - (int)px < wp->xoff + (int)wp->sx - sb_pad - sb_w))) { + (int)px < (int)wp->xoff + (int)wp->sx - sb_pad - sb_w))) { /* Check if in the scrollbar. */ if ((sb_pos == PANE_SCROLLBARS_RIGHT && - ((int)px >= wp->xoff + (int)wp->sx + sb_pad && - (int)px < wp->xoff + (int)wp->sx + sb_pad + sb_w)) || + ((int)px >= (int)wp->xoff + (int)wp->sx + sb_pad && + (int)px < (int)wp->xoff + (int)wp->sx + sb_pad + sb_w)) || (sb_pos == PANE_SCROLLBARS_LEFT && - ((int)px >= wp->xoff - sb_pad - sb_w && - (int)px < wp->xoff - sb_pad))) { + ((int)px >= (int)wp->xoff - sb_pad - sb_w && + (int)px < (int)wp->xoff - sb_pad))) { /* Check where inside the scrollbar. */ - sl_top = wp->yoff + (int)wp->sb_slider_y; - sl_bottom = wp->yoff + (int)wp->sb_slider_y + - (int)wp->sb_slider_h - 1; + sl_top = wp->yoff + wp->sb_slider_y; + sl_bottom = (wp->yoff + wp->sb_slider_y + + wp->sb_slider_h - 1); if ((int)py < sl_top) - return (SCROLLBAR_UP); + return (KEYC_MOUSE_LOCATION_SCROLLBAR_UP); else if ((int)py >= sl_top && (int)py <= sl_bottom) { - *sl_mpos = ((int)py - (int)wp->sb_slider_y - - wp->yoff); - return (SCROLLBAR_SLIDER); + *sl_mpos = (py - wp->sb_slider_y - wp->yoff); + return (KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER); } else /* py > sl_bottom */ - return (SCROLLBAR_DOWN); + return (KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN); } else if (wp->flags & PANE_FLOATING && ((int)px == wp->xoff - 1 || (int)py == wp->yoff - 1 || (int)py == wp->yoff + (int)wp->sy)) { /* Floating pane left, bottom or top border. */ - return (BORDER); + return (KEYC_MOUSE_LOCATION_BORDER); } else { /* Must be inside the pane. */ - return (PANE); + return (KEYC_MOUSE_LOCATION_PANE); } - } else if (~w->flags & WINDOW_ZOOMED) { - /* Try the pane borders if not zoomed. */ + } else { + /* Try the pane borders. */ TAILQ_FOREACH(fwp, &w->panes, entry) { + if ((w->flags & WINDOW_ZOOMED) && + (~fwp->flags & PANE_ZOOMED)) + continue; + bdr_top = fwp->yoff - 1; + bdr_bottom = fwp->yoff + (int)fwp->sy; if (sb_pos == PANE_SCROLLBARS_LEFT) bdr_right = fwp->xoff + (int)fwp->sx; else @@ -712,42 +704,35 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, } } if (fwp != NULL) - return (BORDER); + return (KEYC_MOUSE_LOCATION_BORDER); } - return (NOWHERE); + return (KEYC_MOUSE_LOCATION_NOWHERE); } /* Check for mouse keys. */ static key_code server_client_check_mouse(struct client *c, struct key_event *event) { - struct mouse_event *m = &event->m; - struct session *s = c->session, *fs; - struct window *w = s->curw->window; - struct winlink *fwl; - struct window_pane *wp, *fwp; - u_int x, y, b, sx, sy, px, py, sl_mpos = 0; - int ignore = 0; - key_code key; - struct timeval tv; - struct style_range *sr; - enum { NOTYPE, - MOVE, - DOWN, - UP, - DRAG, - WHEEL, - SECOND, - DOUBLE, - TRIPLE } type = NOTYPE; - enum mouse_where where = NOWHERE; + struct mouse_event *m = &event->m; + struct session *s = c->session, *fs; + struct window *w = s->curw->window; + struct winlink *fwl; + struct window_pane *wp, *fwp; + u_int x, y, sx, sy, px, py, n, sl_mpos = 0; + u_int b, bn; + int ignore = 0; + key_code key; + struct timeval tv; + struct style_range *sr; + enum key_code_type type = KEYC_TYPE_NOTYPE; + enum key_code_mouse_location loc = KEYC_MOUSE_LOCATION_NOWHERE; log_debug("%s mouse %02x at %u,%u (last %u,%u) (%d)", c->name, m->b, m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag); /* What type of event is this? */ if (event->key == KEYC_DOUBLECLICK) { - type = DOUBLE; + type = KEYC_TYPE_DOUBLECLICK; x = m->x, y = m->y, b = m->b; ignore = 1; log_debug("double-click at %u,%u", x, y); @@ -758,11 +743,11 @@ server_client_check_mouse(struct client *c, struct key_event *event) MOUSE_DRAG(m->b) && MOUSE_RELEASE(m->b) && MOUSE_RELEASE(m->lb))) { - type = MOVE; + type = KEYC_TYPE_MOUSEMOVE; x = m->x, y = m->y, b = 0; log_debug("move at %u,%u", x, y); } else if (MOUSE_DRAG(m->b)) { - type = DRAG; + type = KEYC_TYPE_MOUSEDRAG; if (c->tty.mouse_drag_flag) { x = m->x, y = m->y, b = m->b; if (x == m->lx && y == m->ly) @@ -773,11 +758,14 @@ server_client_check_mouse(struct client *c, struct key_event *event) log_debug("drag start at %u,%u", x, y); } } else if (MOUSE_WHEEL(m->b)) { - type = WHEEL; + if ((m->b & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_UP) + type = KEYC_TYPE_WHEELUP; + else + type = KEYC_TYPE_WHEELDOWN; x = m->x, y = m->y, b = m->b; log_debug("wheel at %u,%u", x, y); } else if (MOUSE_RELEASE(m->b)) { - type = UP; + type = KEYC_TYPE_MOUSEUP; x = m->x, y = m->y, b = m->lb; if (m->sgr_type == 'm') b = m->sgr_b; @@ -786,22 +774,22 @@ server_client_check_mouse(struct client *c, struct key_event *event) if (c->flags & CLIENT_DOUBLECLICK) { evtimer_del(&c->click_timer); c->flags &= ~CLIENT_DOUBLECLICK; - type = SECOND; + type = KEYC_TYPE_SECONDCLICK; x = m->x, y = m->y, b = m->b; log_debug("second-click at %u,%u", x, y); c->flags |= CLIENT_TRIPLECLICK; } else if (c->flags & CLIENT_TRIPLECLICK) { evtimer_del(&c->click_timer); c->flags &= ~CLIENT_TRIPLECLICK; - type = TRIPLE; + type = KEYC_TYPE_TRIPLECLICK; x = m->x, y = m->y, b = m->b; log_debug("triple-click at %u,%u", x, y); goto have_event; } /* DOWN is the only remaining event type. */ - if (type == NOTYPE) { - type = DOWN; + if (type == KEYC_TYPE_NOTYPE) { + type = KEYC_TYPE_MOUSEDOWN; x = m->x, y = m->y, b = m->b; log_debug("down at %u,%u", x, y); c->flags |= CLIENT_DOUBLECLICK; @@ -809,7 +797,7 @@ server_client_check_mouse(struct client *c, struct key_event *event) } have_event: - if (type == NOTYPE) + if (type == KEYC_TYPE_NOTYPE) return (KEYC_UNKNOWN); /* Save the session. */ @@ -826,18 +814,18 @@ have_event: y < m->statusat + m->statuslines) { sr = status_get_range(c, x, y - m->statusat); if (sr == NULL) { - where = STATUS_DEFAULT; + loc = KEYC_MOUSE_LOCATION_STATUS_DEFAULT; } else { switch (sr->type) { case STYLE_RANGE_NONE: return (KEYC_UNKNOWN); case STYLE_RANGE_LEFT: log_debug("mouse range: left"); - where = STATUS_LEFT; + loc = KEYC_MOUSE_LOCATION_STATUS_LEFT; break; case STYLE_RANGE_RIGHT: log_debug("mouse range: right"); - where = STATUS_RIGHT; + loc = KEYC_MOUSE_LOCATION_STATUS_RIGHT; break; case STYLE_RANGE_PANE: fwp = window_pane_find_by_id(sr->argument); @@ -846,7 +834,7 @@ have_event: m->wp = sr->argument; log_debug("mouse range: pane %%%u", m->wp); - where = STATUS; + loc = KEYC_MOUSE_LOCATION_STATUS; break; case STYLE_RANGE_WINDOW: fwl = winlink_find_by_index(&s->windows, @@ -856,7 +844,7 @@ have_event: m->w = fwl->window->id; log_debug("mouse range: window @%u", m->w); - where = STATUS; + loc = KEYC_MOUSE_LOCATION_STATUS; break; case STYLE_RANGE_SESSION: fs = session_find_by_id(sr->argument); @@ -865,10 +853,16 @@ have_event: m->s = sr->argument; log_debug("mouse range: session $%u", m->s); - where = STATUS; + loc = KEYC_MOUSE_LOCATION_STATUS; break; case STYLE_RANGE_USER: - where = STATUS; + log_debug("mouse range: user"); + loc = KEYC_MOUSE_LOCATION_STATUS; + break; + case STYLE_RANGE_CONTROL: + n = sr->argument; /* parsing keeps this < 10 */ + log_debug("mouse range: control %u", n); + loc = KEYC_MOUSE_LOCATION_CONTROL0 + n; break; } } @@ -878,9 +872,9 @@ have_event: * Not on status line. Adjust position and check for border, pane, or * scrollbar. */ - if (where == NOWHERE) { + if (loc == KEYC_MOUSE_LOCATION_NOWHERE) { if (c->tty.mouse_scrolling_flag) { - where = SCROLLBAR_SLIDER; + loc = KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER; m->wp = c->tty.mouse_wp->id; m->w = c->tty.mouse_wp->window->id; } else { @@ -900,7 +894,7 @@ have_event: px = px + m->ox; py = py + m->oy; - if (type == DRAG && + if (type == KEYC_TYPE_MOUSEDRAG && c->tty.mouse_wp != NULL) /* Use pane from last mouse event. */ wp = c->tty.mouse_wp; @@ -909,17 +903,23 @@ have_event: wp = window_get_active_at(w, px, py); if (wp == NULL) return (KEYC_UNKNOWN); - where = server_client_check_mouse_in_pane(wp, px, py, + loc = server_client_check_mouse_in_pane(wp, px, py, &sl_mpos); - if (where == PANE) { + if (loc == KEYC_MOUSE_LOCATION_PANE) { log_debug("mouse %u,%u on pane %%%u", x, y, wp->id); - } else if (where == BORDER) + } else if (loc == KEYC_MOUSE_LOCATION_BORDER) { + sr = window_pane_border_status_get_range(wp, px, + py); + if (sr != NULL) { + n = sr->argument; + loc = KEYC_MOUSE_LOCATION_CONTROL0 + n; + } log_debug("mouse on pane %%%u border", wp->id); - else if (where == SCROLLBAR_UP || - where == SCROLLBAR_SLIDER || - where == SCROLLBAR_DOWN) { + } else if (loc == KEYC_MOUSE_LOCATION_SCROLLBAR_UP || + loc == KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER || + loc == KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN) { log_debug("mouse on pane %%%u scrollbar", wp->id); } @@ -929,23 +929,23 @@ have_event: } /* Reset click type or add a click timer if needed. */ - if (type == DOWN || - type == SECOND || - type == TRIPLE) { - if (type != DOWN && + if (type == KEYC_TYPE_MOUSEDOWN || + type == KEYC_TYPE_SECONDCLICK || + type == KEYC_TYPE_TRIPLECLICK) { + if (type != KEYC_TYPE_MOUSEDOWN && (m->b != c->click_button || - where != (enum mouse_where)c->click_where || + loc != (enum key_code_mouse_location)c->click_loc || m->wp != c->click_wp)) { - type = DOWN; + type = KEYC_TYPE_MOUSEDOWN; log_debug("click sequence reset at %u,%u", x, y); c->flags &= ~CLIENT_TRIPLECLICK; c->flags |= CLIENT_DOUBLECLICK; } - if (type != TRIPLE && KEYC_CLICK_TIMEOUT != 0) { + if (type != KEYC_TYPE_TRIPLECLICK && KEYC_CLICK_TIMEOUT != 0) { memcpy(&c->click_event, m, sizeof c->click_event); c->click_button = m->b; - c->click_where = where; + c->click_loc = loc; c->click_wp = m->wp; log_debug("click timer started"); @@ -956,11 +956,14 @@ have_event: } } + key = KEYC_UNKNOWN; + /* Stop dragging if needed. */ - if (type != DRAG && - type != WHEEL && - type != DOUBLE && - type != TRIPLE && + if (type != KEYC_TYPE_MOUSEDRAG && + type != KEYC_TYPE_WHEELUP && + type != KEYC_TYPE_WHEELDOWN && + type != KEYC_TYPE_DOUBLECLICK && + type != KEYC_TYPE_TRIPLECLICK && c->tty.mouse_drag_flag != 0) { if (c->tty.mouse_drag_release != NULL) c->tty.mouse_drag_release(c, m); @@ -973,376 +976,27 @@ have_event: * End a mouse drag by passing a MouseDragEnd key corresponding * to the button that started the drag. */ - switch (c->tty.mouse_drag_flag - 1) { - case MOUSE_BUTTON_1: - if (where == PANE) - key = KEYC_MOUSEDRAGEND1_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND1_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND1_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND1_BORDER; - break; - case MOUSE_BUTTON_2: - if (where == PANE) - key = KEYC_MOUSEDRAGEND2_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND2_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND2_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND2_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND2_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND2_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND2_BORDER; - break; - case MOUSE_BUTTON_3: - if (where == PANE) - key = KEYC_MOUSEDRAGEND3_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND3_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND3_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND3_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND3_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND3_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND3_BORDER; - break; - case MOUSE_BUTTON_6: - if (where == PANE) - key = KEYC_MOUSEDRAGEND6_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND6_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND6_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND6_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND6_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND6_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND6_BORDER; - break; - case MOUSE_BUTTON_7: - if (where == PANE) - key = KEYC_MOUSEDRAGEND7_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND7_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND7_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND7_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND7_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND7_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND7_BORDER; - break; - case MOUSE_BUTTON_8: - if (where == PANE) - key = KEYC_MOUSEDRAGEND8_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND8_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND8_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND8_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND8_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND8_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND8_BORDER; - break; - case MOUSE_BUTTON_9: - if (where == PANE) - key = KEYC_MOUSEDRAGEND9_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND9_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND9_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND9_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND9_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND9_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND9_BORDER; - break; - case MOUSE_BUTTON_10: - if (where == PANE) - key = KEYC_MOUSEDRAGEND10_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND10_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND10_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND10_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND10_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND10_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND10_BORDER; - break; - case MOUSE_BUTTON_11: - if (where == PANE) - key = KEYC_MOUSEDRAGEND11_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAGEND11_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAGEND11_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAGEND11_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAGEND11_STATUS_DEFAULT; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAGEND11_SCROLLBAR_SLIDER; - if (where == BORDER) - key = KEYC_MOUSEDRAGEND11_BORDER; - break; - default: - key = KEYC_MOUSE; - break; - } + type = KEYC_TYPE_MOUSEDRAGEND; c->tty.mouse_drag_flag = 0; c->tty.mouse_wp = NULL; c->tty.mouse_slider_mpos = -1; - goto out; } /* Convert to a key binding. */ - key = KEYC_UNKNOWN; - switch (type) { - case NOTYPE: - break; - case MOVE: - if (where == PANE) { - key = KEYC_MOUSEMOVE_PANE; - if (wp != NULL && - wp != w->active && - options_get_number(s->options, "focus-follows-mouse")) { - window_redraw_active_switch(w, wp); - window_set_active_pane(w, wp, 1); - server_redraw_window_borders(w); - server_status_window(w); - } + if (type == KEYC_TYPE_MOUSEMOVE && loc == KEYC_MOUSE_LOCATION_PANE) { + key = KEYC_MOUSEMOVE_PANE; + if (wp != NULL && + wp != w->active && + options_get_number(s->options, "focus-follows-mouse")) { + window_redraw_active_switch(w, wp); /* xxx needed? */ + window_set_active_pane(w, wp, 1); + server_redraw_window_borders(w); + server_status_window(w); } - if (where == STATUS) - key = KEYC_MOUSEMOVE_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEMOVE_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEMOVE_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEMOVE_STATUS_DEFAULT; - if (where == BORDER) - key = KEYC_MOUSEMOVE_BORDER; - break; - case DRAG: + } + if (type == KEYC_TYPE_MOUSEDRAG) { if (c->tty.mouse_drag_update != NULL) key = KEYC_DRAGGING; - else { - switch (MOUSE_BUTTONS(b)) { - case MOUSE_BUTTON_1: - if (where == PANE) - key = KEYC_MOUSEDRAG1_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG1_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG1_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG1_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG1_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG1_BORDER; - break; - case MOUSE_BUTTON_2: - if (where == PANE) - key = KEYC_MOUSEDRAG2_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG2_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG2_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG2_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG2_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG2_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG2_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG2_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG2_BORDER; - break; - case MOUSE_BUTTON_3: - if (where == PANE) - key = KEYC_MOUSEDRAG3_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG3_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG3_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG3_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG3_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG3_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG3_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG3_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG3_BORDER; - break; - case MOUSE_BUTTON_6: - if (where == PANE) - key = KEYC_MOUSEDRAG6_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG6_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG6_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG6_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG6_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG6_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG6_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG6_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG6_BORDER; - break; - case MOUSE_BUTTON_7: - if (where == PANE) - key = KEYC_MOUSEDRAG7_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG7_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG7_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG7_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG7_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG7_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG7_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG7_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG7_BORDER; - break; - case MOUSE_BUTTON_8: - if (where == PANE) - key = KEYC_MOUSEDRAG8_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG8_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG8_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG8_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG8_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG8_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG8_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG8_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG8_BORDER; - break; - case MOUSE_BUTTON_9: - if (where == PANE) - key = KEYC_MOUSEDRAG9_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG9_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG9_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG9_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG9_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG9_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG9_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG9_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG9_BORDER; - break; - case MOUSE_BUTTON_10: - if (where == PANE) - key = KEYC_MOUSEDRAG10_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG10_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG10_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG10_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG10_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG10_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG10_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG10_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG10_BORDER; - break; - case MOUSE_BUTTON_11: - if (where == PANE) - key = KEYC_MOUSEDRAG11_PANE; - if (where == STATUS) - key = KEYC_MOUSEDRAG11_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDRAG11_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDRAG11_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDRAG11_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDRAG11_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDRAG11_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDRAG11_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDRAG11_BORDER; - break; - } - } /* * Begin a drag by setting the flag to a non-zero value that @@ -1357,7 +1011,7 @@ have_event: c->tty.mouse_wp = wp; } if (c->tty.mouse_scrolling_flag == 0 && - where == SCROLLBAR_SLIDER) { + loc == KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER) { c->tty.mouse_scrolling_flag = 1; if (m->statusat == 0) { c->tty.mouse_slider_mpos = sl_mpos + @@ -1365,961 +1019,33 @@ have_event: } else c->tty.mouse_slider_mpos = sl_mpos; } - 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 == STATUS_LEFT) - key = KEYC_WHEELUP_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_WHEELUP_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_WHEELUP_STATUS_DEFAULT; - if (where == BORDER) - key = KEYC_WHEELUP_BORDER; - } else { - if (where == PANE) - key = KEYC_WHEELDOWN_PANE; - if (where == STATUS) - key = KEYC_WHEELDOWN_STATUS; - if (where == STATUS_LEFT) - key = KEYC_WHEELDOWN_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_WHEELDOWN_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_WHEELDOWN_STATUS_DEFAULT; - if (where == BORDER) - key = KEYC_WHEELDOWN_BORDER; - } - break; - case UP: - switch (MOUSE_BUTTONS(b)) { - case MOUSE_BUTTON_1: - if (where == PANE) - key = KEYC_MOUSEUP1_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP1_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP1_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP1_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP1_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP1_BORDER; - break; - case MOUSE_BUTTON_2: - if (where == PANE) - key = KEYC_MOUSEUP2_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP2_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP2_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP2_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP2_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP2_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP2_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP2_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP2_BORDER; - break; - case MOUSE_BUTTON_3: - if (where == PANE) - key = KEYC_MOUSEUP3_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP3_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP3_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP3_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP3_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP3_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP3_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP3_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP3_BORDER; - break; - case MOUSE_BUTTON_6: - if (where == PANE) - key = KEYC_MOUSEUP6_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP6_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP6_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP6_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP6_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP6_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP6_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP6_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP6_BORDER; - break; - case MOUSE_BUTTON_7: - if (where == PANE) - key = KEYC_MOUSEUP7_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP7_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP7_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP7_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP7_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP7_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP7_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP7_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP7_BORDER; - break; - case MOUSE_BUTTON_8: - if (where == PANE) - key = KEYC_MOUSEUP8_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP8_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP8_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP8_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP8_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP8_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP8_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP8_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP8_BORDER; - break; - case MOUSE_BUTTON_9: - if (where == PANE) - key = KEYC_MOUSEUP9_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP9_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP9_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP9_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP9_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP9_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP9_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP9_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP9_BORDER; - break; - case MOUSE_BUTTON_10: - if (where == PANE) - key = KEYC_MOUSEUP1_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP10_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP10_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP10_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP1_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP1_BORDER; - break; - case MOUSE_BUTTON_11: - if (where == PANE) - key = KEYC_MOUSEUP11_PANE; - if (where == STATUS) - key = KEYC_MOUSEUP11_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEUP11_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEUP11_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP11_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEUP11_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEUP11_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEUP11_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEUP11_BORDER; - break; - } - break; - case DOWN: - switch (MOUSE_BUTTONS(b)) { - case MOUSE_BUTTON_1: - if (where == PANE) - key = KEYC_MOUSEDOWN1_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN1_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN1_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN1_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN1_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN1_BORDER; - break; - case MOUSE_BUTTON_2: - if (where == PANE) - key = KEYC_MOUSEDOWN2_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN2_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN2_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN2_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN2_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN2_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN2_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN2_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN2_BORDER; - break; - case MOUSE_BUTTON_3: - if (where == PANE) - key = KEYC_MOUSEDOWN3_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN3_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN3_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN3_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN3_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN3_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN3_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN3_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN3_BORDER; - break; - case MOUSE_BUTTON_6: - if (where == PANE) - key = KEYC_MOUSEDOWN6_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN6_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN6_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN6_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN6_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN6_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN6_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN6_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN6_BORDER; - break; - case MOUSE_BUTTON_7: - if (where == PANE) - key = KEYC_MOUSEDOWN7_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN7_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN7_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN7_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN7_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN7_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN7_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN7_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN7_BORDER; - break; - case MOUSE_BUTTON_8: - if (where == PANE) - key = KEYC_MOUSEDOWN8_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN8_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN8_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN8_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN8_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN8_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN8_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN8_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN8_BORDER; - break; - case MOUSE_BUTTON_9: - if (where == PANE) - key = KEYC_MOUSEDOWN9_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN9_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN9_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN9_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN9_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN9_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN9_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN9_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN9_BORDER; - break; - case MOUSE_BUTTON_10: - if (where == PANE) - key = KEYC_MOUSEDOWN10_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN10_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN10_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN10_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN10_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN10_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN10_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN10_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN10_BORDER; - break; - case MOUSE_BUTTON_11: - if (where == PANE) - key = KEYC_MOUSEDOWN11_PANE; - if (where == STATUS) - key = KEYC_MOUSEDOWN11_STATUS; - if (where == STATUS_LEFT) - key = KEYC_MOUSEDOWN11_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_MOUSEDOWN11_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_MOUSEDOWN11_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_MOUSEDOWN11_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_MOUSEDOWN11_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_MOUSEDOWN11_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_MOUSEDOWN11_BORDER; - break; - } - break; - case SECOND: - switch (MOUSE_BUTTONS(b)) { - case MOUSE_BUTTON_1: - if (where == PANE) - key = KEYC_SECONDCLICK1_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK1_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK1_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK1_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK1_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK1_BORDER; - break; - case MOUSE_BUTTON_2: - if (where == PANE) - key = KEYC_SECONDCLICK2_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK2_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK2_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK2_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK2_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK2_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK2_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK2_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK2_BORDER; - break; - case MOUSE_BUTTON_3: - if (where == PANE) - key = KEYC_SECONDCLICK3_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK3_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK3_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK3_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK3_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK3_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK3_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK3_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK3_BORDER; - break; - case MOUSE_BUTTON_6: - if (where == PANE) - key = KEYC_SECONDCLICK6_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK6_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK6_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK6_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK6_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK6_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK6_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK6_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK6_BORDER; - break; - case MOUSE_BUTTON_7: - if (where == PANE) - key = KEYC_SECONDCLICK7_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK7_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK7_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK7_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK7_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK7_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK7_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK7_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK7_BORDER; - break; - case MOUSE_BUTTON_8: - if (where == PANE) - key = KEYC_SECONDCLICK8_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK8_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK8_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK8_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK8_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK8_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK8_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK8_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK8_BORDER; - break; - case MOUSE_BUTTON_9: - if (where == PANE) - key = KEYC_SECONDCLICK9_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK9_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK9_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK9_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK9_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK9_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK9_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK9_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK9_BORDER; - break; - case MOUSE_BUTTON_10: - if (where == PANE) - key = KEYC_SECONDCLICK10_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK10_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK10_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK10_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK10_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK10_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK10_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK10_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK10_BORDER; - break; - case MOUSE_BUTTON_11: - if (where == PANE) - key = KEYC_SECONDCLICK11_PANE; - if (where == STATUS) - key = KEYC_SECONDCLICK11_STATUS; - if (where == STATUS_LEFT) - key = KEYC_SECONDCLICK11_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_SECONDCLICK11_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_SECONDCLICK11_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_SECONDCLICK11_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_SECONDCLICK11_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_SECONDCLICK11_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_SECONDCLICK11_BORDER; - break; - } - break; - case DOUBLE: - switch (MOUSE_BUTTONS(b)) { - case MOUSE_BUTTON_1: - if (where == PANE) - key = KEYC_DOUBLECLICK1_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK1_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK1_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK1_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK1_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK1_BORDER; - break; - case MOUSE_BUTTON_2: - if (where == PANE) - key = KEYC_DOUBLECLICK2_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK2_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK2_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK2_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK2_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK2_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK2_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK2_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK2_BORDER; - break; - case MOUSE_BUTTON_3: - if (where == PANE) - key = KEYC_DOUBLECLICK3_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK3_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK3_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK3_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK3_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK3_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK3_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK3_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK3_BORDER; - break; - case MOUSE_BUTTON_6: - if (where == PANE) - key = KEYC_DOUBLECLICK6_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK6_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK6_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK6_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK6_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK6_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK6_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK6_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK6_BORDER; - break; - case MOUSE_BUTTON_7: - if (where == PANE) - key = KEYC_DOUBLECLICK7_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK7_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK7_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK7_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK7_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK7_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK7_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK7_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK7_BORDER; - break; - case MOUSE_BUTTON_8: - if (where == PANE) - key = KEYC_DOUBLECLICK8_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK8_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK8_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK8_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK8_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK8_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK8_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK8_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK8_BORDER; - break; - case MOUSE_BUTTON_9: - if (where == PANE) - key = KEYC_DOUBLECLICK9_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK9_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK9_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK9_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK9_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK9_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK9_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK9_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK9_BORDER; - break; - case MOUSE_BUTTON_10: - if (where == PANE) - key = KEYC_DOUBLECLICK10_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK10_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK10_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK10_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK10_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK10_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK10_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK10_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK10_BORDER; - break; - case MOUSE_BUTTON_11: - if (where == PANE) - key = KEYC_DOUBLECLICK11_PANE; - if (where == STATUS) - key = KEYC_DOUBLECLICK11_STATUS; - if (where == STATUS_LEFT) - key = KEYC_DOUBLECLICK11_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_DOUBLECLICK11_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_DOUBLECLICK11_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_DOUBLECLICK11_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_DOUBLECLICK11_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_DOUBLECLICK11_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_DOUBLECLICK11_BORDER; - break; - } - break; - case TRIPLE: - switch (MOUSE_BUTTONS(b)) { - case MOUSE_BUTTON_1: - if (where == PANE) - key = KEYC_TRIPLECLICK1_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK1_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK1_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK1_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK1_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK1_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK1_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK1_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK1_BORDER; - break; - case MOUSE_BUTTON_2: - if (where == PANE) - key = KEYC_TRIPLECLICK2_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK2_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK2_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK2_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK2_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK2_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK2_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK2_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK2_BORDER; - break; - case MOUSE_BUTTON_3: - if (where == PANE) - key = KEYC_TRIPLECLICK3_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK3_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK3_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK3_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK3_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK3_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK3_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK3_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK3_BORDER; - break; - case MOUSE_BUTTON_6: - if (where == PANE) - key = KEYC_TRIPLECLICK6_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK6_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK6_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK6_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK6_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK6_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK6_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK6_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK6_BORDER; - break; - case MOUSE_BUTTON_7: - if (where == PANE) - key = KEYC_TRIPLECLICK7_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK7_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK7_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK7_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK7_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK7_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK7_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK7_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK7_BORDER; - break; - case MOUSE_BUTTON_8: - if (where == PANE) - key = KEYC_TRIPLECLICK8_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK8_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK8_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK8_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK8_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK8_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK8_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK8_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK8_BORDER; - break; - case MOUSE_BUTTON_9: - if (where == PANE) - key = KEYC_TRIPLECLICK9_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK9_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK9_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK9_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK9_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK9_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK9_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK9_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK9_BORDER; - break; - case MOUSE_BUTTON_10: - if (where == PANE) - key = KEYC_TRIPLECLICK10_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK10_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK10_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK10_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK10_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK10_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK10_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK10_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK10_BORDER; - break; - case MOUSE_BUTTON_11: - if (where == PANE) - key = KEYC_TRIPLECLICK11_PANE; - if (where == STATUS) - key = KEYC_TRIPLECLICK11_STATUS; - if (where == STATUS_LEFT) - key = KEYC_TRIPLECLICK11_STATUS_LEFT; - if (where == STATUS_RIGHT) - key = KEYC_TRIPLECLICK11_STATUS_RIGHT; - if (where == STATUS_DEFAULT) - key = KEYC_TRIPLECLICK11_STATUS_DEFAULT; - if (where == SCROLLBAR_UP) - key = KEYC_TRIPLECLICK11_SCROLLBAR_UP; - if (where == SCROLLBAR_SLIDER) - key = KEYC_TRIPLECLICK11_SCROLLBAR_SLIDER; - if (where == SCROLLBAR_DOWN) - key = KEYC_TRIPLECLICK11_SCROLLBAR_DOWN; - if (where == BORDER) - key = KEYC_TRIPLECLICK11_BORDER; - break; - } - break; } - if (key == KEYC_UNKNOWN) - return (KEYC_UNKNOWN); -out: + if (key == KEYC_UNKNOWN) { + /* Adjust the button number. */ + if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_1) + bn = 1; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_2) + bn = 2; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_3) + bn = 3; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_6) + bn = 6; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_7) + bn = 7; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_8) + bn = 8; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_9) + bn = 9; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_10) + bn = 10; + else if (MOUSE_BUTTONS(b) == MOUSE_BUTTON_11) + bn = 11; + else + bn = 0; + key = KEYC_MAKE_MOUSE_KEY(type, bn, loc); + } + /* Apply modifiers if any. */ if (b & MOUSE_MASK_META) key |= KEYC_META; @@ -2663,6 +1389,15 @@ try_again: } forward_key: + if (wp != NULL && + (wp->flags & PANE_EXITED) && + !KEYC_IS_MOUSE(key) && + !KEYC_IS_PASTE(key) && + options_get_number(wp->options, "remain-on-exit") == 3) { + options_set_number(wp->options, "remain-on-exit", 0); + server_destroy_pane(wp, 0); + goto out; + } if (c->flags & CLIENT_READONLY) goto out; if (wp != NULL && diff --git a/server-fn.c b/server-fn.c index b08ebbf2..bf5a91fc 100644 --- a/server-fn.c +++ b/server-fn.c @@ -339,14 +339,13 @@ server_destroy_pane(struct window_pane *wp, int notify) switch (remain_on_exit) { case 0: break; - case 3: /* keypress — fall through to draw remain-on-exit-format message */ - /* FALLTHROUGH */ case 2: if (remain_on_exit == 2 && WIFEXITED(wp->status) && WEXITSTATUS(wp->status) == 0) break; /* FALLTHROUGH */ case 1: + case 3: if (wp->flags & PANE_STATUSDRAWN) return; wp->flags |= PANE_STATUSDRAWN; diff --git a/sort.c b/sort.c index 1b18d370..8a8f7028 100644 --- a/sort.c +++ b/sort.c @@ -505,6 +505,7 @@ sort_get_panes_session(struct session *s, u_int *n, i = 0; RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; TAILQ_FOREACH(wp, &w->panes, entry) { if (lsz <= i) { lsz += 100; diff --git a/status.c b/status.c index cd8c62be..c39d0d8f 100644 --- a/status.c +++ b/status.c @@ -284,27 +284,10 @@ struct style_range * status_get_range(struct client *c, u_int x, u_int y) { struct status_line *sl = &c->status; - struct style_range *sr; if (y >= nitems(sl->entries)) return (NULL); - TAILQ_FOREACH(sr, &sl->entries[y].ranges, entry) { - if (x >= sr->start && x < sr->end) - return (sr); - } - return (NULL); -} - -/* Free all ranges. */ -static void -status_free_ranges(struct style_ranges *srs) -{ - struct style_range *sr, *sr1; - - TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) { - TAILQ_REMOVE(srs, sr, entry); - free(sr); - } + return (style_ranges_get_range(&sl->entries[y].ranges, x)); } /* Save old status line. */ @@ -341,7 +324,7 @@ status_init(struct client *c) u_int i; for (i = 0; i < nitems(sl->entries); i++) - TAILQ_INIT(&sl->entries[i].ranges); + style_ranges_init(&sl->entries[i].ranges); screen_init(&sl->screen, c->tty.sx, 1, 0); sl->active = &sl->screen; @@ -355,7 +338,7 @@ status_free(struct client *c) u_int i; for (i = 0; i < nitems(sl->entries); i++) { - status_free_ranges(&sl->entries[i].ranges); + style_ranges_free(&sl->entries[i].ranges); free((void *)sl->entries[i].expanded); } @@ -374,7 +357,7 @@ int status_redraw(struct client *c) { struct status_line *sl = &c->status; - struct status_line_entry *sle; + struct style_line_entry *sle; struct session *s = c->session; struct screen_write_ctx ctx; struct grid_cell gc; @@ -454,7 +437,7 @@ status_redraw(struct client *c) screen_write_putc(&ctx, &gc, ' '); screen_write_cursormove(&ctx, 0, i, 0); - status_free_ranges(&sle->ranges); + style_ranges_free(&sle->ranges); format_draw(&ctx, &gc, width, expanded, &sle->ranges, 0); diff --git a/style.c b/style.c index 394eaf32..586e9f93 100644 --- a/style.c +++ b/style.c @@ -137,6 +137,15 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->range_type = STYLE_RANGE_RIGHT; sy->range_argument = 0; style_set_range_string(sy, ""); + } else if (strcasecmp(tmp + 6, "control") == 0) { + if (found == NULL) + goto error; + n = strtonum(found, 0, 9, &errstr); + if (errstr != NULL) + goto error; + sy->range_type = STYLE_RANGE_CONTROL; + sy->range_argument = n; + style_set_range_string(sy, ""); } else if (strcasecmp(tmp + 6, "pane") == 0) { if (found == NULL) goto error; @@ -426,8 +435,10 @@ style_copy(struct style *dst, struct style *src) memcpy(dst, src, sizeof *dst); } +/* Set scrollbar style from an option. */ void -style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo) +style_set_scrollbar_style_from_option(struct style *sb_style, + struct options *oo) { struct style *sy; @@ -446,3 +457,37 @@ style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER); } } + +/* Initialize style ranges. */ +void +style_ranges_init(struct style_ranges *srs) +{ + TAILQ_INIT(srs); +} + +/* Free style ranges. */ +void +style_ranges_free(struct style_ranges *srs) +{ + struct style_range *sr, *sr1; + + TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) { + TAILQ_REMOVE(srs, sr, entry); + free(sr); + } +} + +/* Get range for position from style ranges. */ +struct style_range * +style_ranges_get_range(struct style_ranges *srs, u_int x) +{ + struct style_range *sr; + + if (srs == NULL) + return (NULL); + TAILQ_FOREACH(sr, srs, entry) { + if (x >= sr->start && x < sr->end) + return (sr); + } + return (NULL); +} diff --git a/tmux.1 b/tmux.1 index 8f0fdc2d..c3f0d9b2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5769,7 +5769,7 @@ uses when the colour with that index is requested. The index may be from zero to 255. .Pp .It Xo Ic remain\-on\-exit -.Op Ic on | off | failed | keypress +.Op Ic on | off | failed | key .Xc A pane with this flag set is not destroyed when the program running in it exits. @@ -5777,9 +5777,8 @@ If set to .Ic failed , then only when the program exit status is not zero. If set to -.Ic keypress , -the pane stays open and closes when the user presses any key (other than -a mouse button or paste). +.Ic key , +the pane stays open and closes when a key is pressed. The pane may be reactivated with the .Ic respawn\-pane command. @@ -6013,8 +6012,13 @@ and a location suffix, one of the following: .It Li "ScrollbarSlider" Ta "the scrollbar slider" .It Li "ScrollbarUp" Ta "above the scrollbar slider" .It Li "ScrollbarDown" Ta "below the scrollbar slider" +.It Li "ControlN" Ta "on control range N" .El .Pp +See the +.Sx STYLES +section for information on control ranges. +.Pp The following mouse events are available: .Bl -column "MouseDown1" "MouseDrag1" "WheelDown" -offset indent .It Li "WheelUp" Ta "WheelDown" Ta "" @@ -6475,6 +6479,7 @@ The following variables are available, where appropriate: .It Li "alternate_on" Ta "" Ta "1 if pane is in alternate screen" .It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen" .It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen" +.It Li "bracket_paste_flag" Ta "" Ta "Pane bracketed paste flag" .It Li "buffer_created" Ta "" Ta "Time buffer created" .It Li "buffer_full" Ta "" Ta "Full buffer content" .It Li "buffer_name" Ta "" Ta "Name of buffer" @@ -6600,6 +6605,8 @@ The following variables are available, where appropriate: .It Li "pane_pid" Ta "" Ta "PID of first process in pane" .It Li "pane_pipe" Ta "" Ta "1 if pane is being piped" .It Li "pane_pipe_pid" Ta "" Ta "PID of pipe process, if any" +.It Li "pane_pb_state" Ta "" Ta "Pane progress bar state, one of hidden, normal, error, indeterminate, paused (can be set by application)" +.It Li "pane_pb_progress" Ta "" Ta "Pane progress bar progress percentage (can be set by application)" .It Li "pane_right" Ta "" Ta "Right of pane" .It Li "pane_search_string" Ta "" Ta "Last search string in copy mode" .It Li "pane_start_command" Ta "" Ta "Command pane started with" @@ -6828,6 +6835,7 @@ replaces the previous saved default). .Ic range=window|X , .Ic range=pane|X , .Ic range=user|X , +.Ic range=control|N , .Ic norange .Xc Mark a range for mouse events in the @@ -6874,6 +6882,19 @@ will be available in the format variable. .Ql X must be at most 15 bytes in length. +.Pp +.Ic range=control|N +is a set of ranges for users to define custom behavior. +.Ql N +can be 0 through 9. +When a mouse event occurs in the +.Ic range=control|N +range, the +.Ql ControlN +key binding is triggered. +See +.Sx MOUSE SUPPORT +for details. .It Ic set\-default Set the current colours and attributes as the default, overwriting any previous default. @@ -7403,7 +7424,7 @@ If is not given, the .Ic display\-time option is used; a delay of zero waits for a key press. -.Ql N +.Fl N ignores key presses and closes only after the delay expires. If .Fl C diff --git a/tmux.h b/tmux.h index 3b958237..b2a7016f 100644 --- a/tmux.h +++ b/tmux.h @@ -129,18 +129,6 @@ struct winlink; #define VISUAL_ON 1 #define VISUAL_BOTH 2 -/* No key or unknown key. */ -#define KEYC_NONE 0x000ff000000000ULL -#define KEYC_UNKNOWN 0x000fe000000000ULL - -/* - * Base for special (that is, not Unicode) keys. An enum must be at most a - * signed int, so these are based in the highest Unicode PUA. - */ -#define KEYC_BASE 0x0000000010e000ULL -#define KEYC_USER 0x0000000010f000ULL -#define KEYC_USER_END (KEYC_USER + KEYC_NUSER) - /* Key modifier bits. */ #define KEYC_META 0x00100000000000ULL #define KEYC_CTRL 0x00200000000000ULL @@ -156,45 +144,122 @@ struct winlink; #define KEYC_SENT 0x40000000000000ULL /* Masks for key bits. */ -#define KEYC_MASK_MODIFIERS 0x00f00000000000ULL +#define KEYC_MASK_TYPE 0x0000ff00000000ULL +#define KEYC_MASK_MODIFIERS 0x00ff0000000000ULL #define KEYC_MASK_FLAGS 0xff000000000000ULL -#define KEYC_MASK_KEY 0x000fffffffffffULL +#define KEYC_MASK_KEY 0x0000ffffffffffULL -/* Available user keys. */ -#define KEYC_NUSER 1000 +#define KEYC_NUSER 1000 +#define KEYC_SHIFT_TYPE(t) ((unsigned long long)(t) << 32) +#define KEYC_IS_TYPE(k, t) (((k) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(t)) +enum key_code_type { + KEYC_TYPE_UNICODE, + KEYC_TYPE_USER, + KEYC_TYPE_FUNCTION, + KEYC_TYPE_MOUSEMOVE, + KEYC_TYPE_MOUSEDOWN, + KEYC_TYPE_MOUSEUP, + KEYC_TYPE_MOUSEDRAG, + KEYC_TYPE_MOUSEDRAGEND, + KEYC_TYPE_WHEELDOWN, + KEYC_TYPE_WHEELUP, + KEYC_TYPE_SECONDCLICK, + KEYC_TYPE_DOUBLECLICK, + KEYC_TYPE_TRIPLECLICK, + KEYC_TYPE_NOTYPE /* end */ +}; -/* Is this a mouse key? */ -#define KEYC_IS_MOUSE(key) \ - (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \ - ((key) & KEYC_MASK_KEY) < KEYC_BSPACE) +enum key_code_mouse_location { + KEYC_MOUSE_LOCATION_PANE, + KEYC_MOUSE_LOCATION_STATUS, + KEYC_MOUSE_LOCATION_STATUS_LEFT, + KEYC_MOUSE_LOCATION_STATUS_RIGHT, + KEYC_MOUSE_LOCATION_STATUS_DEFAULT, + KEYC_MOUSE_LOCATION_BORDER, + KEYC_MOUSE_LOCATION_SCROLLBAR_UP, + KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER, + KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN, + KEYC_MOUSE_LOCATION_CONTROL0, /* keep order */ + KEYC_MOUSE_LOCATION_CONTROL1, + KEYC_MOUSE_LOCATION_CONTROL2, + KEYC_MOUSE_LOCATION_CONTROL3, + KEYC_MOUSE_LOCATION_CONTROL4, + KEYC_MOUSE_LOCATION_CONTROL5, + KEYC_MOUSE_LOCATION_CONTROL6, + KEYC_MOUSE_LOCATION_CONTROL7, + KEYC_MOUSE_LOCATION_CONTROL8, + KEYC_MOUSE_LOCATION_CONTROL9, + KEYC_MOUSE_LOCATION_NOWHERE /* end */ +}; /* Is this a Unicode key? */ #define KEYC_IS_UNICODE(key) \ - (((key) & KEYC_MASK_KEY) > 0x7f && \ - (((key) & KEYC_MASK_KEY) < KEYC_BASE || \ - ((key) & KEYC_MASK_KEY) >= KEYC_BASE_END) && \ - (((key) & KEYC_MASK_KEY) < KEYC_USER || \ - ((key) & KEYC_MASK_KEY) >= KEYC_USER_END)) + (((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_UNICODE) && \ + ((key) & KEYC_MASK_KEY) > 0x7f) + +/* Is this a user key? */ +#define KEYC_IS_USER(key) \ + (((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_USER)) + +/* Is this a function key? */ +#define KEYC_IS_SPECIAL(key) \ + (((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_FUNCTION)) + +/* Is this a mouse key? */ +#define KEYC_IS_MOUSE(key) \ + (((key) & KEYC_MASK_KEY) == KEYC_MOUSE || \ + (((key) & KEYC_MASK_TYPE) >= KEYC_SHIFT_TYPE(KEYC_TYPE_MOUSEMOVE) && \ + ((key) & KEYC_MASK_TYPE) <= KEYC_SHIFT_TYPE(KEYC_TYPE_TRIPLECLICK))) /* Is this a paste key? */ #define KEYC_IS_PASTE(key) \ - (((key) & KEYC_MASK_KEY) == KEYC_PASTE_START || \ - ((key) & KEYC_MASK_KEY) == KEYC_PASTE_END) + (((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_FUNCTION) && \ + (((key) & KEYC_MASK_KEY) == KEYC_PASTE_START || \ + ((key) & KEYC_MASK_KEY) == KEYC_PASTE_END)) /* Multiple click timeout. */ #define KEYC_CLICK_TIMEOUT 300 +/* Bit shift for mouse events. */ +#define KEYC_MOUSE_LOCATION_SHIFT 0 +#define KEYC_MOUSE_BUTTON_SHIFT 8 + /* Mouse key codes. */ -#define KEYC_MOUSE_KEY(name) \ - KEYC_ ## name ## _PANE, \ - KEYC_ ## name ## _STATUS, \ - KEYC_ ## name ## _STATUS_LEFT, \ - KEYC_ ## name ## _STATUS_RIGHT, \ - KEYC_ ## name ## _STATUS_DEFAULT, \ - KEYC_ ## name ## _SCROLLBAR_UP, \ - KEYC_ ## name ## _SCROLLBAR_SLIDER, \ - KEYC_ ## name ## _SCROLLBAR_DOWN, \ - KEYC_ ## name ## _BORDER +#define KEYC_MOUSE_KEYS(t) \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, PANE), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS_LEFT), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS_RIGHT), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS_DEFAULT), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, BORDER), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_UP), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_SLIDER), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_DOWN), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL0), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL1), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL2), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL3), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL4), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL5), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL6), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL7), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL8), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL9) +#define KEYC_MOUSE_KEY(p, t, l) \ + p ## _ ## l = KEYC_MAKE_MOUSE_KEY(t, 0, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 1_ ## l = KEYC_MAKE_MOUSE_KEY(t, 1, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 2_ ## l = KEYC_MAKE_MOUSE_KEY(t, 2, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 3_ ## l = KEYC_MAKE_MOUSE_KEY(t, 3, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 6_ ## l = KEYC_MAKE_MOUSE_KEY(t, 6, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 7_ ## l = KEYC_MAKE_MOUSE_KEY(t, 7, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 8_ ## l = KEYC_MAKE_MOUSE_KEY(t, 8, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 9_ ## l = KEYC_MAKE_MOUSE_KEY(t, 9, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 10_ ## l = KEYC_MAKE_MOUSE_KEY(t, 10, KEYC_MOUSE_LOCATION_ ## l), \ + p ## 11_ ## l = KEYC_MAKE_MOUSE_KEY(t, 11, KEYC_MOUSE_LOCATION_ ## l) +#define KEYC_MAKE_MOUSE_KEY(t, b, l) \ + ((KEYC_SHIFT_TYPE(t)) | \ + ((unsigned long long)(b) << KEYC_MOUSE_BUTTON_SHIFT) | \ + ((unsigned long long)(l) << KEYC_MOUSE_LOCATION_SHIFT)) #define KEYC_MOUSE_STRING(name, s) \ { #s "Pane", KEYC_ ## name ## _PANE }, \ { #s "Status", KEYC_ ## name ## _STATUS }, \ @@ -204,7 +269,17 @@ struct winlink; { #s "ScrollbarUp", KEYC_ ## name ## _SCROLLBAR_UP }, \ { #s "ScrollbarSlider", KEYC_ ## name ## _SCROLLBAR_SLIDER }, \ { #s "ScrollbarDown", KEYC_ ## name ## _SCROLLBAR_DOWN }, \ - { #s "Border", KEYC_ ## name ## _BORDER } + { #s "Border", KEYC_ ## name ## _BORDER }, \ + { #s "Control0", KEYC_ ## name ## _CONTROL0 }, \ + { #s "Control1", KEYC_ ## name ## _CONTROL1 }, \ + { #s "Control2", KEYC_ ## name ## _CONTROL2 }, \ + { #s "Control3", KEYC_ ## name ## _CONTROL3 }, \ + { #s "Control4", KEYC_ ## name ## _CONTROL4 }, \ + { #s "Control5", KEYC_ ## name ## _CONTROL5 }, \ + { #s "Control6", KEYC_ ## name ## _CONTROL6 }, \ + { #s "Control7", KEYC_ ## name ## _CONTROL7 }, \ + { #s "Control8", KEYC_ ## name ## _CONTROL8 }, \ + { #s "Control9", KEYC_ ## name ## _CONTROL9 } /* * A single key. This can be ASCII or Unicode or one of the keys between @@ -250,8 +325,15 @@ enum { /* Special key codes. */ enum { + /* User key code range. */ + KEYC_USER = KEYC_SHIFT_TYPE(KEYC_TYPE_USER), + + /* Functional key code range. */ + KEYC_NONE = KEYC_SHIFT_TYPE(KEYC_TYPE_FUNCTION), + KEYC_UNKNOWN, + /* Focus events. */ - KEYC_FOCUS_IN = KEYC_BASE, + KEYC_FOCUS_IN, KEYC_FOCUS_OUT, /* "Any" key, used if not found in key table. */ @@ -261,77 +343,6 @@ enum { KEYC_PASTE_START, KEYC_PASTE_END, - /* Mouse keys. */ - KEYC_MOUSE, /* unclassified mouse event */ - KEYC_DRAGGING, /* dragging in progress */ - KEYC_DOUBLECLICK, /* double click complete */ - KEYC_MOUSE_KEY(MOUSEMOVE), - KEYC_MOUSE_KEY(MOUSEDOWN1), - KEYC_MOUSE_KEY(MOUSEDOWN2), - KEYC_MOUSE_KEY(MOUSEDOWN3), - KEYC_MOUSE_KEY(MOUSEDOWN6), - KEYC_MOUSE_KEY(MOUSEDOWN7), - KEYC_MOUSE_KEY(MOUSEDOWN8), - KEYC_MOUSE_KEY(MOUSEDOWN9), - KEYC_MOUSE_KEY(MOUSEDOWN10), - KEYC_MOUSE_KEY(MOUSEDOWN11), - KEYC_MOUSE_KEY(MOUSEUP1), - KEYC_MOUSE_KEY(MOUSEUP2), - KEYC_MOUSE_KEY(MOUSEUP3), - KEYC_MOUSE_KEY(MOUSEUP6), - KEYC_MOUSE_KEY(MOUSEUP7), - KEYC_MOUSE_KEY(MOUSEUP8), - KEYC_MOUSE_KEY(MOUSEUP9), - KEYC_MOUSE_KEY(MOUSEUP10), - KEYC_MOUSE_KEY(MOUSEUP11), - KEYC_MOUSE_KEY(MOUSEDRAG1), - KEYC_MOUSE_KEY(MOUSEDRAG2), - KEYC_MOUSE_KEY(MOUSEDRAG3), - KEYC_MOUSE_KEY(MOUSEDRAG6), - KEYC_MOUSE_KEY(MOUSEDRAG7), - KEYC_MOUSE_KEY(MOUSEDRAG8), - KEYC_MOUSE_KEY(MOUSEDRAG9), - KEYC_MOUSE_KEY(MOUSEDRAG10), - KEYC_MOUSE_KEY(MOUSEDRAG11), - KEYC_MOUSE_KEY(MOUSEDRAGEND1), - KEYC_MOUSE_KEY(MOUSEDRAGEND2), - KEYC_MOUSE_KEY(MOUSEDRAGEND3), - KEYC_MOUSE_KEY(MOUSEDRAGEND6), - KEYC_MOUSE_KEY(MOUSEDRAGEND7), - KEYC_MOUSE_KEY(MOUSEDRAGEND8), - KEYC_MOUSE_KEY(MOUSEDRAGEND9), - KEYC_MOUSE_KEY(MOUSEDRAGEND10), - KEYC_MOUSE_KEY(MOUSEDRAGEND11), - KEYC_MOUSE_KEY(WHEELUP), - KEYC_MOUSE_KEY(WHEELDOWN), - KEYC_MOUSE_KEY(SECONDCLICK1), - KEYC_MOUSE_KEY(SECONDCLICK2), - KEYC_MOUSE_KEY(SECONDCLICK3), - KEYC_MOUSE_KEY(SECONDCLICK6), - KEYC_MOUSE_KEY(SECONDCLICK7), - KEYC_MOUSE_KEY(SECONDCLICK8), - KEYC_MOUSE_KEY(SECONDCLICK9), - KEYC_MOUSE_KEY(SECONDCLICK10), - KEYC_MOUSE_KEY(SECONDCLICK11), - KEYC_MOUSE_KEY(DOUBLECLICK1), - KEYC_MOUSE_KEY(DOUBLECLICK2), - KEYC_MOUSE_KEY(DOUBLECLICK3), - KEYC_MOUSE_KEY(DOUBLECLICK6), - KEYC_MOUSE_KEY(DOUBLECLICK7), - KEYC_MOUSE_KEY(DOUBLECLICK8), - KEYC_MOUSE_KEY(DOUBLECLICK9), - KEYC_MOUSE_KEY(DOUBLECLICK10), - KEYC_MOUSE_KEY(DOUBLECLICK11), - KEYC_MOUSE_KEY(TRIPLECLICK1), - KEYC_MOUSE_KEY(TRIPLECLICK2), - KEYC_MOUSE_KEY(TRIPLECLICK3), - KEYC_MOUSE_KEY(TRIPLECLICK6), - KEYC_MOUSE_KEY(TRIPLECLICK7), - KEYC_MOUSE_KEY(TRIPLECLICK8), - KEYC_MOUSE_KEY(TRIPLECLICK9), - KEYC_MOUSE_KEY(TRIPLECLICK10), - KEYC_MOUSE_KEY(TRIPLECLICK11), - /* Backspace key. */ KEYC_BSPACE, @@ -384,8 +395,22 @@ enum { KEYC_REPORT_DARK_THEME, KEYC_REPORT_LIGHT_THEME, - /* End of special keys. */ - KEYC_BASE_END + /* Mouse state. */ + KEYC_MOUSE, /* unclassified mouse event */ + KEYC_DRAGGING, /* dragging in progress */ + KEYC_DOUBLECLICK, /* double click complete */ + + /* Mouse key code ranges. Must be at the end. */ + KEYC_MOUSE_KEYS(MOUSEMOVE), + KEYC_MOUSE_KEYS(WHEELDOWN), + KEYC_MOUSE_KEYS(WHEELUP), + KEYC_MOUSE_KEYS(MOUSEDOWN), + KEYC_MOUSE_KEYS(MOUSEUP), + KEYC_MOUSE_KEYS(MOUSEDRAG), + KEYC_MOUSE_KEYS(MOUSEDRAGEND), + KEYC_MOUSE_KEYS(SECONDCLICK), + KEYC_MOUSE_KEYS(DOUBLECLICK), + KEYC_MOUSE_KEYS(TRIPLECLICK), }; /* Termcap codes. */ @@ -880,7 +905,8 @@ enum style_range_type { STYLE_RANGE_PANE, STYLE_RANGE_WINDOW, STYLE_RANGE_SESSION, - STYLE_RANGE_USER + STYLE_RANGE_USER, + STYLE_RANGE_CONTROL }; struct style_range { enum style_range_type type; @@ -894,6 +920,12 @@ struct style_range { }; TAILQ_HEAD(style_ranges, style_range); +/* Ranges connected with a status line. */ +struct style_line_entry { + char *expanded; + struct style_ranges ranges; +}; + /* Default style width and pad. */ #define STYLE_WIDTH_DEFAULT -1 #define STYLE_PAD_DEFAULT -1 @@ -952,6 +984,20 @@ enum screen_cursor_style { SCREEN_CURSOR_BAR }; + +/* Progress bar, OSC 9;4. */ +enum progress_bar_state { + PROGRESS_BAR_HIDDEN = 0, + PROGRESS_BAR_NORMAL = 1, + PROGRESS_BAR_ERROR = 2, + PROGRESS_BAR_INDETERMINATE = 3, + PROGRESS_BAR_PAUSED = 4 +}; +struct progress_bar { + enum progress_bar_state state; + int progress; +}; + /* Virtual screen. */ struct screen_sel; struct screen_titles; @@ -993,6 +1039,7 @@ struct screen { struct screen_write_cline *write_list; struct hyperlinks *hyperlinks; + struct progress_bar progress_bar; }; /* Screen write context. */ @@ -1216,8 +1263,8 @@ struct window_pane { #define PANE_DROP 0x2 #define PANE_FOCUSED 0x4 #define PANE_VISITED 0x8 -/* 0x10 unused */ -/* 0x20 unused */ +#define PANE_ZOOMED 0x10 +#define PANE_FLOATING 0x20 #define PANE_INPUTOFF 0x40 #define PANE_CHANGED 0x80 #define PANE_EXITED 0x100 @@ -1228,9 +1275,7 @@ struct window_pane { #define PANE_THEMECHANGED 0x2000 #define PANE_UNSEENCHANGES 0x4000 #define PANE_REDRAWSCROLLBAR 0x8000 -#define PANE_FLOATING 0x10000 #define PANE_MINIMISED 0x20000 -#define PANE_ZOOMED 0x40000 #define PANE_SAVED_FLOAT 0x80000 /* saved_float_* fields are valid */ /* Last floating position/size, saved when the pane is tiled. */ @@ -1268,6 +1313,7 @@ struct window_pane { struct grid_cell cached_active_gc; struct colour_palette palette; enum client_theme last_theme; + struct style_line_entry border_status_line; int pipe_fd; pid_t pipe_pid; @@ -1892,10 +1938,6 @@ struct cmd_entry { /* Status line. */ #define STATUS_LINES_LIMIT 5 -struct status_line_entry { - char *expanded; - struct style_ranges ranges; -}; struct status_line { struct event timer; @@ -1904,7 +1946,7 @@ struct status_line { int references; struct grid_cell style; - struct status_line_entry entries[STATUS_LINES_LIMIT]; + struct style_line_entry entries[STATUS_LINES_LIMIT]; }; /* Prompt type. */ @@ -1969,6 +2011,7 @@ typedef void (*overlay_resize_cb)(struct client *, void *); struct client { const char *name; struct tmuxpeer *peer; + const char *user; struct cmdq_list *queue; struct client_windows windows; @@ -2009,7 +2052,7 @@ struct client { struct event repeat_timer; struct event click_timer; - int click_where; + int click_loc; int click_wp; u_int click_button; struct mouse_event click_event; @@ -3312,6 +3355,7 @@ int screen_set_title(struct screen *, const char *); void screen_set_path(struct screen *, const char *); void screen_push_title(struct screen *); void screen_pop_title(struct screen *); +void screen_set_progress_bar(struct screen *, enum progress_bar_state, int); void screen_resize(struct screen *, u_int, u_int, int); void screen_resize_cursor(struct screen *, u_int, u_int, int, int, int); void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int, @@ -3324,7 +3368,7 @@ int screen_select_cell(struct screen *, struct grid_cell *, void screen_alternate_on(struct screen *, struct grid_cell *, int); void screen_alternate_off(struct screen *, struct grid_cell *, int); const char *screen_mode_to_string(int); -const char *screen_print(struct screen *); +const char *screen_print(struct screen *, int); /* window.c */ extern struct windows windows; @@ -3404,7 +3448,7 @@ int window_pane_exited(struct window_pane *); u_int window_pane_search(struct window_pane *, const char *, int, int); const char *window_printable_flags(struct winlink *, int); -const char *window_pane_printable_flags(struct window_pane *, int); +const char *window_pane_printable_flags(struct window_pane *); struct window_pane *window_pane_find_up(struct window_pane *); struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); @@ -3435,6 +3479,8 @@ int window_pane_get_bg_control_client(struct window_pane *); int window_get_bg_client(struct window_pane *); enum client_theme window_pane_get_theme(struct window_pane *); void window_pane_send_theme_update(struct window_pane *); +struct style_range *window_pane_border_status_get_range(struct window_pane *, + u_int, u_int); /* layout.c */ u_int layout_count_cells(struct layout_cell *); @@ -3756,6 +3802,9 @@ void style_set(struct style *, const struct grid_cell *); void style_copy(struct style *, struct style *); void style_set_scrollbar_style_from_option(struct style *, struct options *); +void style_ranges_init(struct style_ranges *); +void style_ranges_free(struct style_ranges *); +struct style_range *style_ranges_get_range(struct style_ranges *, u_int); /* spawn.c */ struct winlink *spawn_window(struct spawn_context *, char **); diff --git a/tty-draw.c b/tty-draw.c index bd643f98..b5ecbe50 100644 --- a/tty-draw.c +++ b/tty-draw.c @@ -143,6 +143,14 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__, px, py, nx, atx, aty); + /* There is no point in drawing more than the end of the terminal. */ + if (atx >= tty->sx) + return; + if (atx + nx >= tty->sx) + nx = tty->sx - atx; + if (nx == 0) + return; + /* * Clamp the width to cellsize - note this is not cellused, because * there may be empty background cells after it (from BCE). @@ -150,19 +158,24 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, cellsize = grid_get_line(gd, gd->hsize + py)->cellsize; if (screen_size_x(s) > cellsize) ex = cellsize; - else { + else ex = screen_size_x(s); - if (px > ex) - return; - if (px + nx > ex) - nx = ex - px; - } - if (ex < nx) - ex = nx; log_debug("%s: drawing %u-%u,%u (end %u) at %u,%u; defaults: fg=%d, " "bg=%d", __func__, px, px + nx, py, ex, atx, aty, defaults->fg, defaults->bg); + /* Turn off cursor while redrawing and reset region and margins. */ + flags = (tty->flags & TTY_NOCURSOR); + tty->flags |= TTY_NOCURSOR; + tty_update_mode(tty, tty->mode, s); + tty_region_off(tty); + tty_margin_off(tty); + + /* Start with the default cell as the last cell. */ + memcpy(&last, &grid_default_cell, sizeof last); + last.bg = defaults->bg; + tty_default_attributes(tty, defaults, palette, 8, s->hyperlinks); + /* * If there is padding at the start, we must have truncated a wide * character. Clear it. @@ -195,7 +208,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, log_debug("%s: clearing %u padding cells", __func__, cx); tty_draw_line_clear(tty, atx, aty, cx, defaults, bg, 0); if (cx == ex) - return; + goto out; atx += cx; px += cx; nx -= cx; @@ -209,18 +222,6 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, wrapped = 1; } - /* Turn off cursor while redrawing and reset region and margins. */ - flags = (tty->flags & TTY_NOCURSOR); - tty->flags |= TTY_NOCURSOR; - tty_update_mode(tty, tty->mode, s); - tty_region_off(tty); - tty_margin_off(tty); - - /* Start with the default cell as the last cell. */ - memcpy(&last, &grid_default_cell, sizeof last); - last.bg = defaults->bg; - tty_default_attributes(tty, defaults, palette, 8, s->hyperlinks); - /* Loop over each character in the range. */ last_i = i = 0; len = 0; @@ -252,7 +253,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, } /* Work out the the empty width. */ - if (i >= ex) + if (px >= ex || i >= ex - px) empty = 1; else if (gcp->bg != last.bg) empty = 0; @@ -331,6 +332,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, i += gcp->data.width; } +out: tty->flags = (tty->flags & ~TTY_NOCURSOR)|flags; tty_update_mode(tty, tty->mode, s); } diff --git a/tty-features.c b/tty-features.c index 31d9b7a8..c620c383 100644 --- a/tty-features.c +++ b/tty-features.c @@ -474,23 +474,46 @@ tty_default_features(int *feat, const char *name, u_int version) #define TTY_FEATURES_BASE_MODERN_XTERM \ "256,RGB,bpaste,clipboard,mouse,strikethrough,title" { .name = "mintty", - .features = TTY_FEATURES_BASE_MODERN_XTERM - ",ccolour,cstyle,extkeys,margins,overline,usstyle" + .features = TTY_FEATURES_BASE_MODERN_XTERM "," + "ccolour," + "cstyle," + "extkeys," + "margins," + "overline," + "usstyle" }, { .name = "tmux", - .features = TTY_FEATURES_BASE_MODERN_XTERM - ",ccolour,cstyle,focus,overline,usstyle,hyperlinks" + .features = TTY_FEATURES_BASE_MODERN_XTERM "," + "ccolour," + "cstyle," + "extkeys," + "focus," + "overline," + "usstyle," + "hyperlinks" }, { .name = "rxvt-unicode", - .features = "256,bpaste,ccolour,cstyle,mouse,title,ignorefkeys" + .features = "256," + "bpaste," + "ccolour," + "cstyle," + "mouse," + "title," + "ignorefkeys" }, { .name = "iTerm2", - .features = TTY_FEATURES_BASE_MODERN_XTERM - ",cstyle,extkeys,margins,usstyle,sync,osc7,hyperlinks" + .features = TTY_FEATURES_BASE_MODERN_XTERM "," + "cstyle," + "extkeys," + "margins," + "usstyle," + "sync," + "osc7,hyperlinks" }, { .name = "foot", - .features = TTY_FEATURES_BASE_MODERN_XTERM - ",cstyle,extkeys" + .features = TTY_FEATURES_BASE_MODERN_XTERM "," + "cstyle," + "extkeys" }, { .name = "XTerm", /* @@ -498,8 +521,11 @@ tty_default_features(int *feat, const char *name, u_int version) * disabled so not set it here - they will be added if * secondary DA shows VT420. */ - .features = TTY_FEATURES_BASE_MODERN_XTERM - ",ccolour,cstyle,extkeys,focus" + .features = TTY_FEATURES_BASE_MODERN_XTERM "," + "ccolour," + "cstyle," + "extkeys," + "focus" } }; u_int i; diff --git a/tty-keys.c b/tty-keys.c index 8fc51174..05ec63c8 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1383,7 +1383,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) copy[end] = '\0'; /* Convert from base64. */ - needed = (end / 4) * 3; + needed = ((end + 3) / 4) * 3; if (needed == 0) { free(copy); return (0); diff --git a/window-copy.c b/window-copy.c index 9835706d..d5d2b0de 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1034,6 +1034,8 @@ window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy) screen_resize(s, sx, sy, 0); cx = data->cx; + if (data->oy > gd->hsize + data->cy) + data->oy = gd->hsize + data->cy; cy = gd->hsize + data->cy - data->oy; reflow = (gd->sx != sx); if (reflow) @@ -2747,6 +2749,8 @@ window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs) if (data->viewmode) return (WINDOW_COPY_CMD_NOTHING); + if (data->oy > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); oy_from_top = screen_hsize(data->backing) - data->oy; screen_free(data->backing); @@ -3340,7 +3344,7 @@ window_copy_command(struct window_mode_entry *wme, struct client *c, enum window_copy_cmd_clear clear = WINDOW_COPY_CMD_CLEAR_NEVER; const char *command; u_int i, count = args_count(args); - int keys; + int keys, flags; char *error = NULL; if (count == 0) @@ -3362,9 +3366,10 @@ window_copy_command(struct window_mode_entry *wme, struct client *c, action = WINDOW_COPY_CMD_NOTHING; for (i = 0; i < nitems(window_copy_cmd_table); i++) { if (strcmp(window_copy_cmd_table[i].command, command) == 0) { - if (c->flags & CLIENT_READONLY && - (~window_copy_cmd_table[i].flags & - WINDOW_COPY_CMD_FLAG_READONLY)) { + flags = window_copy_cmd_table[i].flags; + if (c != NULL && + c->flags & CLIENT_READONLY && + (~flags & WINDOW_COPY_CMD_FLAG_READONLY)) { status_message_set(c, -1, 1, 0, 0, "client is read-only"); return; diff --git a/window.c b/window.c index 0ec69372..9a856b3f 100644 --- a/window.c +++ b/window.c @@ -653,10 +653,10 @@ struct window_pane * window_get_active_at(struct window *w, u_int x, u_int y) { struct window_pane *wp; - int status, xoff, yoff; + int pane_status, xoff, yoff; u_int sx, sy; - status = options_get_number(w->options, "pane-border-status"); + pane_status = options_get_number(w->options, "pane-border-status"); TAILQ_FOREACH(wp, &w->z_index, zentry) { if (!window_pane_visible(wp)) @@ -667,7 +667,7 @@ window_get_active_at(struct window *w, u_int x, u_int y) right border. */ if ((int)x < xoff || x > xoff + sx) continue; - if (status == PANE_STATUS_TOP) { + if (pane_status == PANE_STATUS_TOP) { if ((int)y < yoff - 1 || y > yoff + sy) continue; } else { @@ -678,8 +678,13 @@ window_get_active_at(struct window *w, u_int x, u_int y) /* Floating, include top or or left border. */ if ((int)x < xoff - 1 || x > xoff + sx) continue; - if ((int)y < yoff - 1 || y > yoff + sy) + if (pane_status == PANE_STATUS_TOP) { + if ((int)y <= yoff - 2 || y > yoff + sy - 1) + continue; + } else { + if ((int)y < yoff - 1 || y > yoff + sy) continue; + } } return (wp); } @@ -990,9 +995,8 @@ window_printable_flags(struct winlink *wl, int escape) { struct session *s = wl->session; static char flags[32]; - int pos; + u_int pos = 0; - pos = 0; if (wl->flags & WINLINK_ACTIVITY) { flags[pos++] = '#'; if (escape) @@ -1015,7 +1019,7 @@ window_printable_flags(struct winlink *wl, int escape) } const char * -window_pane_printable_flags(struct window_pane *wp, __unused int escape) +window_pane_printable_flags(struct window_pane *wp) { static char flags[32]; struct window *w = wp->window; @@ -1099,6 +1103,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) window_pane_default_cursor(wp); screen_init(&wp->status_screen, 1, 1, 0); + style_ranges_init(&wp->border_status_line.ranges); if (gethostname(host, sizeof host) == 0) screen_set_title(&wp->base, host); @@ -1151,6 +1156,7 @@ window_pane_destroy(struct window_pane *wp) free(wp->shell); cmd_free_argv(wp->argc, wp->argv); colour_palette_free(&wp->palette); + style_ranges_free(&wp->border_status_line.ranges); free(wp); } @@ -2121,3 +2127,31 @@ window_pane_send_theme_update(struct window_pane *wp) break; } } + +struct style_range * +window_pane_border_status_get_range(struct window_pane *wp, u_int x, u_int y) +{ + struct style_ranges *srs; + struct window *w = wp->window; + struct options *wo = w->options; + u_int line; + int pane_status; + + if (wp == NULL) + return (NULL); + srs = &wp->border_status_line.ranges; + + pane_status = options_get_number(wo, "pane-border-status"); + if (pane_status == PANE_STATUS_TOP) + line = wp->yoff - 1; + else if (pane_status == PANE_STATUS_BOTTOM) + line = wp->yoff + wp->sy; + if (pane_status == PANE_STATUS_OFF || line != y) + return (NULL); + + /* + * The border formats start 2 off but that isn't reflected in + * the stored bounds of the range. + */ + return (style_ranges_get_range(srs, x - wp->xoff - 2)); +}