mirror of
https://github.com/tmux/tmux.git
synced 2026-09-19 19:38:09 +00:00
Compare commits
16 Commits
kitty-keys
...
no_more_ov
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b98ce20a10 | ||
|
|
5ea118e3e0 | ||
|
|
b15c62ac07 | ||
|
|
7049aa826a | ||
|
|
19320c6969 | ||
|
|
78c0dc5be0 | ||
|
|
81fa44f263 | ||
|
|
ba1bfeeb9c | ||
|
|
5047e4eb1a | ||
|
|
8a1f4620b0 | ||
|
|
7d32e7f379 | ||
|
|
6671efcaf7 | ||
|
|
858a9d7376 | ||
|
|
980877fb5c | ||
|
|
c7a6a735bc | ||
|
|
381eaaa3a3 |
12
CHANGES
12
CHANGES
@@ -111,18 +111,6 @@ CHANGES FROM 3.7c TO 3.8
|
||||
|
||||
* Change show-options and show-hooks to use formats and add a -F flag to each.
|
||||
|
||||
* Add support for the Kitty keyboard protocol. When extended-keys is on,
|
||||
tmux uses it with terminals which support it, detected when a client
|
||||
attaches or set with a new kittykeys terminal feature, and standard
|
||||
extended keys or VT10x keys with other terminals, so terminals with
|
||||
different capabilities may be attached at the same time. Programs inside
|
||||
tmux may ask for either the Kitty protocol or modifyOtherKeys and get keys
|
||||
in the form they asked for. The Kitty protocol can report the Super and
|
||||
Hyper modifiers (key name prefixes s- and H-).
|
||||
|
||||
* Add a client_key_mode format giving the extended key reporting mode in
|
||||
use for a client, alongside the existing pane_key_mode for a pane.
|
||||
|
||||
* Allow individual terminal features to be disabled by adding @ to their names
|
||||
in terminal-features, and add a utf8 feature for terminals which support
|
||||
UTF-8 output.
|
||||
|
||||
@@ -171,7 +171,6 @@ dist_tmux_SOURCES = \
|
||||
grid.c \
|
||||
hooks.c \
|
||||
hyperlinks.c \
|
||||
input-kitty.c \
|
||||
input-keys.c \
|
||||
input.c \
|
||||
job.c \
|
||||
@@ -189,7 +188,6 @@ dist_tmux_SOURCES = \
|
||||
options-table.c \
|
||||
options.c \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
prompt-history.c \
|
||||
prompt.c \
|
||||
@@ -213,7 +211,6 @@ dist_tmux_SOURCES = \
|
||||
tty-acs.c \
|
||||
tty-draw.c \
|
||||
tty-features.c \
|
||||
tty-kitty.c \
|
||||
tty-keys.c \
|
||||
tty-term.c \
|
||||
tty.c \
|
||||
|
||||
@@ -54,8 +54,8 @@ const struct cmd_entry cmd_display_popup_entry = {
|
||||
.name = "display-popup",
|
||||
.alias = "popup",
|
||||
|
||||
.args = { "Bb:Cc:d:e:Eh:kNs:S:t:T:w:x:y:", 0, -1, NULL },
|
||||
.usage = "[-BCEkN] [-b border-lines] [-c target-client] "
|
||||
.args = { "Bb:Cc:d:e:Eh:ks:S:t:T:w:x:y:", 0, -1, NULL },
|
||||
.usage = "[-BCEk] [-b border-lines] [-c target-client] "
|
||||
"[-d start-directory] [-e environment] [-h height] "
|
||||
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
|
||||
" [-T title] [-w width] [-x position] [-y position] "
|
||||
@@ -91,203 +91,6 @@ cmd_display_menu_args_parse(struct args *args, u_int idx, __unused char **cause)
|
||||
return (type);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_display_menu_get_popup_pos(struct client *tc, struct cmdq_item *item,
|
||||
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
|
||||
{
|
||||
struct tty *tty = &tc->tty;
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
struct session *s = tc->session;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window_pane *wp = target->wp;
|
||||
struct style_ranges *ranges = NULL;
|
||||
struct style_range *sr = NULL;
|
||||
const char *xp, *yp;
|
||||
char *p;
|
||||
int top;
|
||||
u_int line, ox, oy, sx, sy, lines, position;
|
||||
long n;
|
||||
struct format_tree *ft;
|
||||
|
||||
/*
|
||||
* Work out the position from the -x and -y arguments. This is the
|
||||
* bottom-left position.
|
||||
*/
|
||||
|
||||
/* If the popup is too big, stop now. */
|
||||
if (w > tty->sx || h > tty->sy)
|
||||
return (0);
|
||||
|
||||
/* Create format with mouse position if any. */
|
||||
ft = format_create_from_target(item);
|
||||
if (event->m.valid) {
|
||||
format_add(ft, "popup_mouse_x", "%u", event->m.x);
|
||||
format_add(ft, "popup_mouse_y", "%u", event->m.y);
|
||||
}
|
||||
|
||||
/* Position of the previous menu, for -x/-y L. */
|
||||
format_add(ft, "popup_last_x", "%u", target->w->menu_last_px);
|
||||
format_add(ft, "popup_last_y", "%u", target->w->menu_last_py + h);
|
||||
|
||||
/*
|
||||
* If there are any status lines, add this window position and the
|
||||
* status line position.
|
||||
*/
|
||||
top = status_at_line(tc);
|
||||
if (top != -1) {
|
||||
lines = status_line_size(tc);
|
||||
if (top == 0)
|
||||
top = lines;
|
||||
else
|
||||
top = 0;
|
||||
position = options_get_number(s->options, "status-position");
|
||||
|
||||
for (line = 0; line < lines; line++) {
|
||||
ranges = &tc->status.entries[line].ranges;
|
||||
TAILQ_FOREACH(sr, ranges, entry) {
|
||||
if (sr->type != STYLE_RANGE_WINDOW)
|
||||
continue;
|
||||
if (sr->argument == (u_int)wl->idx)
|
||||
break;
|
||||
}
|
||||
if (sr != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sr != NULL) {
|
||||
format_add(ft, "popup_window_status_line_x", "%u",
|
||||
sr->start);
|
||||
if (position == 0) {
|
||||
format_add(ft, "popup_window_status_line_y",
|
||||
"%u", line + 1 + h);
|
||||
} else {
|
||||
format_add(ft, "popup_window_status_line_y",
|
||||
"%u", tty->sy - lines + line);
|
||||
}
|
||||
}
|
||||
|
||||
if (position == 0)
|
||||
format_add(ft, "popup_status_line_y", "%u", lines + h);
|
||||
else {
|
||||
format_add(ft, "popup_status_line_y", "%u",
|
||||
tty->sy - lines);
|
||||
}
|
||||
} else
|
||||
top = 0;
|
||||
|
||||
/* Popup width and height. */
|
||||
format_add(ft, "popup_width", "%u", w);
|
||||
format_add(ft, "popup_height", "%u", h);
|
||||
|
||||
/* Position so popup is in the centre. */
|
||||
n = (long)(tty->sx - 1) / 2 - w / 2;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_centre_x", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_centre_x", "%ld", n);
|
||||
n = (tty->sy - 1) / 2 + h / 2;
|
||||
if (n >= tty->sy)
|
||||
format_add(ft, "popup_centre_y", "%u", tty->sy - h);
|
||||
else
|
||||
format_add(ft, "popup_centre_y", "%ld", n);
|
||||
|
||||
/* Position of popup relative to mouse. */
|
||||
if (event->m.valid) {
|
||||
n = (long)event->m.x - w / 2;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_mouse_centre_x", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_mouse_centre_x", "%ld", n);
|
||||
n = event->m.y - h / 2;
|
||||
if (n + h >= tty->sy) {
|
||||
format_add(ft, "popup_mouse_centre_y", "%u",
|
||||
tty->sy - h);
|
||||
} else
|
||||
format_add(ft, "popup_mouse_centre_y", "%ld", n);
|
||||
n = (long)event->m.y + h;
|
||||
if (n >= tty->sy)
|
||||
format_add(ft, "popup_mouse_top", "%u", tty->sy - 1);
|
||||
else
|
||||
format_add(ft, "popup_mouse_top", "%ld", n);
|
||||
n = event->m.y - h;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_mouse_bottom", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_mouse_bottom", "%ld", n);
|
||||
}
|
||||
|
||||
/* Position in pane. */
|
||||
tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy);
|
||||
n = top + wp->yoff - oy + h;
|
||||
if (n >= tty->sy)
|
||||
format_add(ft, "popup_pane_top", "%u", tty->sy - h);
|
||||
else
|
||||
format_add(ft, "popup_pane_top", "%ld", n);
|
||||
format_add(ft, "popup_pane_bottom", "%u", top + wp->yoff + wp->sy - oy);
|
||||
format_add(ft, "popup_pane_left", "%u", wp->xoff - ox);
|
||||
n = (long)wp->xoff + wp->sx - ox - w;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_pane_right", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_pane_right", "%ld", n);
|
||||
|
||||
/* Expand horizontal position. */
|
||||
xp = args_get(args, 'x');
|
||||
if (xp == NULL || strcmp(xp, "C") == 0)
|
||||
xp = "#{popup_centre_x}";
|
||||
else if (strcmp(xp, "R") == 0)
|
||||
xp = "#{popup_pane_right}";
|
||||
else if (strcmp(xp, "P") == 0)
|
||||
xp = "#{popup_pane_left}";
|
||||
else if (strcmp(xp, "M") == 0)
|
||||
xp = "#{popup_mouse_centre_x}";
|
||||
else if (strcmp(xp, "L") == 0)
|
||||
xp = "#{popup_last_x}";
|
||||
else if (strcmp(xp, "W") == 0)
|
||||
xp = "#{popup_window_status_line_x}";
|
||||
p = format_expand(ft, xp);
|
||||
n = strtol(p, NULL, 10);
|
||||
if (n + w >= tty->sx)
|
||||
n = tty->sx - w;
|
||||
else if (n < 0)
|
||||
n = 0;
|
||||
*px = n;
|
||||
log_debug("%s: -x: %s = %s = %u (-w %u)", __func__, xp, p, *px, w);
|
||||
free(p);
|
||||
|
||||
/* Expand vertical position */
|
||||
yp = args_get(args, 'y');
|
||||
if (yp == NULL || strcmp(yp, "C") == 0)
|
||||
yp = "#{popup_centre_y}";
|
||||
else if (strcmp(yp, "P") == 0)
|
||||
yp = "#{popup_pane_bottom}";
|
||||
else if (strcmp(yp, "M") == 0)
|
||||
yp = "#{popup_mouse_top}";
|
||||
else if (strcmp(yp, "L") == 0)
|
||||
yp = "#{popup_last_y}";
|
||||
else if (strcmp(yp, "S") == 0)
|
||||
yp = "#{popup_status_line_y}";
|
||||
else if (strcmp(yp, "W") == 0)
|
||||
yp = "#{popup_window_status_line_y}";
|
||||
p = format_expand(ft, yp);
|
||||
n = strtol(p, NULL, 10);
|
||||
if (n < h)
|
||||
n = 0;
|
||||
else
|
||||
n -= h;
|
||||
if (n + h >= tty->sy)
|
||||
n = tty->sy - h;
|
||||
else if (n < 0)
|
||||
n = 0;
|
||||
*py = n;
|
||||
log_debug("%s: -y: %s = %s = %u (-h %u)", __func__, yp, p, *py, h);
|
||||
free(p);
|
||||
|
||||
format_free(ft);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_display_menu_get_menu_pos(struct client *tc, struct cmdq_item *item,
|
||||
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
|
||||
@@ -565,6 +368,22 @@ fail:
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum pane_lines
|
||||
cmd_display_popup_get_lines(const char *value, char **cause)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
if (value == NULL)
|
||||
value = "single";
|
||||
else if (strcmp(value, "rounded") == 0)
|
||||
value = "single";
|
||||
else if (strcmp(value, "padded") == 0)
|
||||
value = "spaces";
|
||||
|
||||
oe = options_search("pane-border-lines");
|
||||
return (options_find_choice(oe, value, cause));
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -572,148 +391,199 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct session *s = target->s;
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct tty *tty = &tc->tty;
|
||||
const char *value, *shell, *shellcmd = NULL;
|
||||
const char *style = args_get(args, 's');
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp = target->wp, *new_wp = NULL;
|
||||
struct spawn_context sc = { 0 };
|
||||
struct layout_cell *lc = NULL;
|
||||
struct layout_geometry lg;
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
const char *value, *style = args_get(args, 's');
|
||||
const char *border_style = args_get(args, 'S');
|
||||
char *cwd = NULL, *cause = NULL, **argv = NULL;
|
||||
char *title = NULL;
|
||||
int modify = popup_present(tc);
|
||||
int flags = -1, argc = 0;
|
||||
enum box_lines lines = BOX_LINES_DEFAULT;
|
||||
u_int px, py, w, h, count = args_count(args);
|
||||
char *cause = NULL, *title = NULL;
|
||||
enum pane_lines lines = PANE_LINES_SINGLE;
|
||||
u_int px, py, sx, sy, count = args_count(args);
|
||||
struct args_value *av;
|
||||
struct environ *env = NULL;
|
||||
struct options *o = s->curw->window->options;
|
||||
struct options_entry *oe;
|
||||
long long ll;
|
||||
|
||||
if (args_has(args, 'C')) {
|
||||
server_client_clear_overlay(tc);
|
||||
if (w->modal != NULL)
|
||||
server_kill_pane(w->modal);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (tc->flags & CLIENT_CONTROL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (!modify && tc->overlay_draw != NULL)
|
||||
if (w->modal != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
if (!modify) {
|
||||
h = tty->sy / 2;
|
||||
if (args_has(args, 'h')) {
|
||||
h = args_percentage(args, 'h', 1, tty->sy, tty->sy,
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "height %s", cause);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
w = tty->sx / 2;
|
||||
if (args_has(args, 'w')) {
|
||||
w = args_percentage(args, 'w', 1, tty->sx, tty->sx,
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "width %s", cause);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (w > tty->sx)
|
||||
w = tty->sx;
|
||||
if (h > tty->sy)
|
||||
h = tty->sy;
|
||||
if (!cmd_display_menu_get_popup_pos(tc, item, args, &px, &py,
|
||||
w, h))
|
||||
goto out;
|
||||
|
||||
value = args_get(args, 'd');
|
||||
if (value != NULL)
|
||||
cwd = format_single_from_target(item, value);
|
||||
else
|
||||
cwd = xstrdup(server_client_get_cwd(tc, s));
|
||||
if (count == 0) {
|
||||
shellcmd = options_get_string(s->options,
|
||||
"default-command");
|
||||
} else if (count == 1)
|
||||
shellcmd = args_string(args, 0);
|
||||
if (count <= 1 && (shellcmd == NULL || *shellcmd == '\0')) {
|
||||
shellcmd = NULL;
|
||||
shell = options_get_string(s->options, "default-shell");
|
||||
if (!checkshell(shell))
|
||||
shell = _PATH_BSHELL;
|
||||
cmd_append_argv(&argc, &argv, shell);
|
||||
} else
|
||||
args_to_vector(args, &argc, &argv);
|
||||
|
||||
if (args_has(args, 'e') >= 1) {
|
||||
env = environ_create();
|
||||
av = args_first_value(args, 'e');
|
||||
while (av != NULL) {
|
||||
environ_put(env, av->string, 0);
|
||||
av = args_next_value(av);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = args_get(args, 'b');
|
||||
if (args_has(args, 'B'))
|
||||
lines = BOX_LINES_NONE;
|
||||
lines = PANE_LINES_NONE;
|
||||
else if (value != NULL) {
|
||||
oe = options_get(o, "popup-border-lines");
|
||||
lines = options_find_choice(options_table_entry(oe), value,
|
||||
&cause);
|
||||
lines = cmd_display_popup_get_lines(value, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "popup-border-lines %s", cause);
|
||||
cmdq_error(item, "pane-border-lines %s", cause);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
sy = w->sy / 2;
|
||||
if (args_has(args, 'h')) {
|
||||
ll = args_percentage(args, 'h', 1, w->sy, w->sy, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "height %s", cause);
|
||||
goto fail;
|
||||
}
|
||||
sy = ll;
|
||||
}
|
||||
|
||||
sx = w->sx / 2;
|
||||
if (args_has(args, 'w')) {
|
||||
ll = args_percentage(args, 'w', 1, w->sx, w->sx, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "width %s", cause);
|
||||
goto fail;
|
||||
}
|
||||
sx = ll;
|
||||
}
|
||||
|
||||
if (sx > w->sx)
|
||||
sx = w->sx;
|
||||
if (sy > w->sy)
|
||||
sy = w->sy;
|
||||
if ((lines == PANE_LINES_NONE && (sx < 1 || sy < 1)) ||
|
||||
(lines != PANE_LINES_NONE && (sx < 3 || sy < 3)))
|
||||
goto out;
|
||||
if (!cmd_display_menu_get_menu_pos(tc, item, args, &px, &py, sx, sy))
|
||||
goto out;
|
||||
|
||||
lg.sx = sx;
|
||||
lg.sy = sy;
|
||||
lg.xoff = px;
|
||||
lg.yoff = py;
|
||||
if (lines != PANE_LINES_NONE) {
|
||||
lg.sx -= 2;
|
||||
lg.sy -= 2;
|
||||
lg.xoff++;
|
||||
lg.yoff++;
|
||||
}
|
||||
|
||||
window_push_zoom(w, 0, 1);
|
||||
lc = layout_floating_pane(w, wp, &lg);
|
||||
if (lc == NULL) {
|
||||
window_pop_zoom(w);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sc.item = item;
|
||||
sc.s = s;
|
||||
sc.wl = wl;
|
||||
sc.tc = tc;
|
||||
sc.wp0 = wp;
|
||||
sc.lc = lc;
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'd');
|
||||
sc.flags = (SPAWN_FLOATING|SPAWN_MODAL|SPAWN_FLOATOVERZOOM);
|
||||
|
||||
if (count != 1 || *args_string(args, 0) != '\0')
|
||||
args_to_vector(args, &sc.argc, &sc.argv);
|
||||
sc.environ = environ_create();
|
||||
av = args_first_value(args, 'e');
|
||||
while (av != NULL) {
|
||||
environ_put(sc.environ, av->string, 0);
|
||||
av = args_next_value(av);
|
||||
}
|
||||
|
||||
new_wp = spawn_pane(&sc, &cause);
|
||||
if (new_wp == NULL) {
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
free(cause);
|
||||
cause = NULL;
|
||||
window_pop_zoom(w);
|
||||
goto fail;
|
||||
}
|
||||
window_pop_zoom(w);
|
||||
new_wp->flags |= PANE_CAPTUREALLKEYS;
|
||||
if (!args_has(args, 'E'))
|
||||
new_wp->flags |= PANE_CLOSEONCANCEL;
|
||||
|
||||
options_set_number(new_wp->options, "pane-border-lines", lines);
|
||||
if (args_has(args, 'E') > 1) {
|
||||
if (args_has(args, 'k'))
|
||||
options_set_number(new_wp->options, "remain-on-exit", 4);
|
||||
else
|
||||
options_set_number(new_wp->options, "remain-on-exit", 2);
|
||||
} else if (args_has(args, 'E'))
|
||||
options_set_number(new_wp->options, "remain-on-exit", 0);
|
||||
else if (args_has(args, 'k'))
|
||||
options_set_number(new_wp->options, "remain-on-exit", 3);
|
||||
else
|
||||
options_set_number(new_wp->options, "remain-on-exit", 1);
|
||||
options_set_string(new_wp->options, "remain-on-exit-format", 0, "%s", "");
|
||||
|
||||
if (style != NULL) {
|
||||
if (options_set_string(new_wp->options, "window-style", 0,
|
||||
"%s", style) == NULL) {
|
||||
cmdq_error(item, "bad style: %s", style);
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(new_wp->options, "window-active-style", 0,
|
||||
"%s", style);
|
||||
new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
}
|
||||
if (border_style != NULL) {
|
||||
if (options_set_string(new_wp->options, "pane-border-style", 0,
|
||||
"%s", border_style) == NULL) {
|
||||
cmdq_error(item, "bad border style: %s", border_style);
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(new_wp->options, "pane-active-border-style",
|
||||
0, "%s", border_style);
|
||||
}
|
||||
if (args_has(args, 'T'))
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
else
|
||||
title = xstrdup("");
|
||||
|
||||
if (args_has(args, 'N') || !modify)
|
||||
flags = 0;
|
||||
if (args_has(args, 'E') > 1) {
|
||||
if (flags == -1)
|
||||
flags = 0;
|
||||
flags |= POPUP_CLOSEEXITZERO;
|
||||
} else if (args_has(args, 'E')) {
|
||||
if (flags == -1)
|
||||
flags = 0;
|
||||
flags |= POPUP_CLOSEEXIT;
|
||||
}
|
||||
if (args_has(args, 'k')) {
|
||||
if (flags == -1)
|
||||
flags = 0;
|
||||
flags |= POPUP_CLOSEANYKEY;
|
||||
if (title != NULL) {
|
||||
options_set_number(new_wp->options, "pane-border-status",
|
||||
PANE_STATUS_TOP);
|
||||
options_set_string(new_wp->options, "pane-border-format", 0,
|
||||
"%s", "#{pane_title}");
|
||||
screen_set_title(&new_wp->base, title, 0);
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, new_wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", new_wp);
|
||||
event_payload_set_window(ep, "window", new_wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
}
|
||||
|
||||
if (modify) {
|
||||
popup_modify(tc, title, style, border_style, lines, flags);
|
||||
goto out;
|
||||
}
|
||||
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
|
||||
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0)
|
||||
goto out;
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
new_wp->wait_item = item;
|
||||
server_redraw_session(s);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
free(title);
|
||||
cmd_free_argv(argc, argv);
|
||||
return (CMD_RETURN_WAIT);
|
||||
|
||||
out:
|
||||
cmd_free_argv(argc, argv);
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
free(title);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(cause);
|
||||
cmd_free_argv(argc, argv);
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
if (new_wp != NULL) {
|
||||
server_client_remove_pane(new_wp);
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(new_wp->window, new_wp);
|
||||
}
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
free(title);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
45
format.c
45
format.c
@@ -1617,41 +1617,6 @@ format_cb_client_height(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for client_key_mode. */
|
||||
static void *
|
||||
format_cb_client_key_mode(struct format_tree *ft)
|
||||
{
|
||||
struct client *c = ft->c;
|
||||
const char *mode;
|
||||
char *s;
|
||||
int kitty, eks;
|
||||
|
||||
if (c == NULL || (~c->tty.flags & TTY_STARTED))
|
||||
return (NULL);
|
||||
|
||||
if (c->tty.flags & TTY_KKBPUSHED) {
|
||||
xasprintf(&s, "Kitty %u", c->tty.kitty_keys);
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* This mirrors the choice made in tty_update_features(). */
|
||||
kitty = ((c->tty.term->flags & TERM_KITTYKEYS) != 0);
|
||||
eks = (options_get_number(global_options, "extended-keys") != 0);
|
||||
if (kitty)
|
||||
eks = 0;
|
||||
if (eks && tty_term_has(c->tty.term, TTYC_ENEKS))
|
||||
mode = "Ext";
|
||||
else
|
||||
mode = "VT10x";
|
||||
|
||||
/* The terminal supports Kitty keys but they are not in use. */
|
||||
if (kitty) {
|
||||
xasprintf(&s, "%s (Kitty)", mode);
|
||||
return (s);
|
||||
}
|
||||
return (xstrdup(mode));
|
||||
}
|
||||
|
||||
/* Callback for client_key_table. */
|
||||
static void *
|
||||
format_cb_client_key_table(struct format_tree *ft)
|
||||
@@ -2522,14 +2487,7 @@ format_cb_pane_unseen_changes(struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_pane_key_mode(struct format_tree *ft)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (ft->wp != NULL && ft->wp->screen != NULL) {
|
||||
if (ft->wp->screen->kitty_keys.flags != 0) {
|
||||
xasprintf(&s, "Kitty %u",
|
||||
ft->wp->screen->kitty_keys.flags);
|
||||
return (s);
|
||||
}
|
||||
switch (ft->wp->screen->mode & EXTENDED_KEY_MODES) {
|
||||
case MODE_KEYS_EXTENDED:
|
||||
return (xstrdup("Ext 1"));
|
||||
@@ -3684,9 +3642,6 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "client_height", FORMAT_TABLE_STRING,
|
||||
format_cb_client_height
|
||||
},
|
||||
{ "client_key_mode", FORMAT_TABLE_STRING,
|
||||
format_cb_client_key_mode
|
||||
},
|
||||
{ "client_key_table", FORMAT_TABLE_STRING,
|
||||
format_cb_client_key_table
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||
w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0);
|
||||
wp = window_add_pane(w, NULL, 0, 0);
|
||||
bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty);
|
||||
wp->ictx = input_init(wp, vpty[0], NULL, NULL);
|
||||
wp->ictx = input_init(wp, vpty[0], NULL);
|
||||
window_add_ref(w, __func__);
|
||||
|
||||
wp->fd = open("/dev/null", O_WRONLY);
|
||||
|
||||
11
input-keys.c
11
input-keys.c
@@ -464,8 +464,7 @@ input_key_extended(struct bufferevent *bev, key_code key)
|
||||
} else
|
||||
key &= KEYC_MASK_KEY;
|
||||
|
||||
if (options_get_number(global_options, "extended-keys-format") ==
|
||||
EXTENDED_KEYS_XTERM)
|
||||
if (options_get_number(global_options, "extended-keys-format") == 1)
|
||||
xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key);
|
||||
else
|
||||
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier);
|
||||
@@ -589,10 +588,6 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Kitty keys take precedence if the application asked for them. */
|
||||
if (input_key_kitty(s, bev, key) == 0)
|
||||
return (0);
|
||||
|
||||
/* Is this backspace? */
|
||||
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
|
||||
newkey = options_get_number(global_options, "backspace");
|
||||
@@ -682,10 +677,6 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
log_debug("%s: ignoring key 0x%llx", __func__, key);
|
||||
return (0);
|
||||
}
|
||||
if (key & (KEYC_SUPER|KEYC_HYPER))
|
||||
return (input_key_vt10x(bev, key));
|
||||
if (s->kitty_keys.flags & KITTY_KEY_SUPPORTED)
|
||||
return (input_key_vt10x(bev, key));
|
||||
|
||||
/*
|
||||
* No builtin key sequence; construct an extended key sequence
|
||||
|
||||
313
input-kitty.c
313
input-kitty.c
@@ -1,313 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Michael Grant <mgrant@grant.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Track pane keyboard state and encode keys for applications. */
|
||||
|
||||
struct input_kitty_key {
|
||||
key_code key;
|
||||
u_int number;
|
||||
char final;
|
||||
};
|
||||
|
||||
static const struct input_kitty_key input_kitty_keys[] = {
|
||||
{ C0_ESC, 27, 'u' },
|
||||
{ C0_CR, 13, 'u' },
|
||||
{ C0_HT, 9, 'u' },
|
||||
{ KEYC_BSPACE, 127, 'u' },
|
||||
{ KEYC_IC, 2, '~' },
|
||||
{ KEYC_DC, 3, '~' },
|
||||
{ KEYC_LEFT, 1, 'D' },
|
||||
{ KEYC_RIGHT, 1, 'C' },
|
||||
{ KEYC_UP, 1, 'A' },
|
||||
{ KEYC_DOWN, 1, 'B' },
|
||||
{ KEYC_PPAGE, 5, '~' },
|
||||
{ KEYC_NPAGE, 6, '~' },
|
||||
{ KEYC_HOME, 1, 'H' },
|
||||
{ KEYC_END, 1, 'F' },
|
||||
{ KEYC_F1, 1, 'P' },
|
||||
{ KEYC_F2, 1, 'Q' },
|
||||
{ KEYC_F3, 13, '~' },
|
||||
{ KEYC_F4, 1, 'S' },
|
||||
{ KEYC_F5, 15, '~' },
|
||||
{ KEYC_F6, 17, '~' },
|
||||
{ KEYC_F7, 18, '~' },
|
||||
{ KEYC_F8, 19, '~' },
|
||||
{ KEYC_F9, 20, '~' },
|
||||
{ KEYC_F10, 21, '~' },
|
||||
{ KEYC_F11, 23, '~' },
|
||||
{ KEYC_F12, 24, '~' },
|
||||
{ KEYC_CAPSLOCK, 57358, 'u' },
|
||||
{ KEYC_SCROLLLOCK, 57359, 'u' },
|
||||
{ KEYC_NUMLOCK, 57360, 'u' },
|
||||
{ KEYC_PRINTSCREEN, 57361, 'u' },
|
||||
{ KEYC_PAUSE, 57362, 'u' },
|
||||
{ KEYC_MENU, 57363, 'u' },
|
||||
{ KEYC_F13, 57376, 'u' },
|
||||
{ KEYC_F14, 57377, 'u' },
|
||||
{ KEYC_F15, 57378, 'u' },
|
||||
{ KEYC_F16, 57379, 'u' },
|
||||
{ KEYC_F17, 57380, 'u' },
|
||||
{ KEYC_F18, 57381, 'u' },
|
||||
{ KEYC_F19, 57382, 'u' },
|
||||
{ KEYC_F20, 57383, 'u' },
|
||||
{ KEYC_F21, 57384, 'u' },
|
||||
{ KEYC_F22, 57385, 'u' },
|
||||
{ KEYC_F23, 57386, 'u' },
|
||||
{ KEYC_F24, 57387, 'u' },
|
||||
{ KEYC_F25, 57388, 'u' },
|
||||
{ KEYC_F26, 57389, 'u' },
|
||||
{ KEYC_F27, 57390, 'u' },
|
||||
{ KEYC_F28, 57391, 'u' },
|
||||
{ KEYC_F29, 57392, 'u' },
|
||||
{ KEYC_F30, 57393, 'u' },
|
||||
{ KEYC_F31, 57394, 'u' },
|
||||
{ KEYC_F32, 57395, 'u' },
|
||||
{ KEYC_F33, 57396, 'u' },
|
||||
{ KEYC_F34, 57397, 'u' },
|
||||
{ KEYC_F35, 57398, 'u' },
|
||||
{ KEYC_KP_ZERO|KEYC_KEYPAD, 57399, 'u' },
|
||||
{ KEYC_KP_ONE|KEYC_KEYPAD, 57400, 'u' },
|
||||
{ KEYC_KP_TWO|KEYC_KEYPAD, 57401, 'u' },
|
||||
{ KEYC_KP_THREE|KEYC_KEYPAD, 57402, 'u' },
|
||||
{ KEYC_KP_FOUR|KEYC_KEYPAD, 57403, 'u' },
|
||||
{ KEYC_KP_FIVE|KEYC_KEYPAD, 57404, 'u' },
|
||||
{ KEYC_KP_SIX|KEYC_KEYPAD, 57405, 'u' },
|
||||
{ KEYC_KP_SEVEN|KEYC_KEYPAD, 57406, 'u' },
|
||||
{ KEYC_KP_EIGHT|KEYC_KEYPAD, 57407, 'u' },
|
||||
{ KEYC_KP_NINE|KEYC_KEYPAD, 57408, 'u' },
|
||||
{ KEYC_KP_PERIOD|KEYC_KEYPAD, 57409, 'u' },
|
||||
{ KEYC_KP_SLASH|KEYC_KEYPAD, 57410, 'u' },
|
||||
{ KEYC_KP_STAR|KEYC_KEYPAD, 57411, 'u' },
|
||||
{ KEYC_KP_MINUS|KEYC_KEYPAD, 57412, 'u' },
|
||||
{ KEYC_KP_PLUS|KEYC_KEYPAD, 57413, 'u' },
|
||||
{ KEYC_KP_ENTER|KEYC_KEYPAD, 57414, 'u' },
|
||||
{ KEYC_KP_EQUAL|KEYC_KEYPAD, 57415, 'u' },
|
||||
{ KEYC_KP_SEPARATOR|KEYC_KEYPAD, 57416, 'u' },
|
||||
{ KEYC_KP_LEFT|KEYC_KEYPAD, 57417, 'u' },
|
||||
{ KEYC_KP_RIGHT|KEYC_KEYPAD, 57418, 'u' },
|
||||
{ KEYC_KP_UP|KEYC_KEYPAD, 57419, 'u' },
|
||||
{ KEYC_KP_DOWN|KEYC_KEYPAD, 57420, 'u' },
|
||||
{ KEYC_KP_PPAGE|KEYC_KEYPAD, 57421, 'u' },
|
||||
{ KEYC_KP_NPAGE|KEYC_KEYPAD, 57422, 'u' },
|
||||
{ KEYC_KP_HOME|KEYC_KEYPAD, 57423, 'u' },
|
||||
{ KEYC_KP_END|KEYC_KEYPAD, 57424, 'u' },
|
||||
{ KEYC_KP_IC|KEYC_KEYPAD, 57425, 'u' },
|
||||
{ KEYC_KP_DC|KEYC_KEYPAD, 57426, 'u' },
|
||||
{ KEYC_KP_BEGIN|KEYC_KEYPAD, 57427, '~' },
|
||||
{ KEYC_MEDIA_PLAY, 57428, 'u' },
|
||||
{ KEYC_MEDIA_PAUSE, 57429, 'u' },
|
||||
{ KEYC_MEDIA_PLAYPAUSE, 57430, 'u' },
|
||||
{ KEYC_MEDIA_REVERSE, 57431, 'u' },
|
||||
{ KEYC_MEDIA_STOP, 57432, 'u' },
|
||||
{ KEYC_MEDIA_FASTFORWARD, 57433, 'u' },
|
||||
{ KEYC_MEDIA_REWIND, 57434, 'u' },
|
||||
{ KEYC_MEDIA_NEXT, 57435, 'u' },
|
||||
{ KEYC_MEDIA_PREVIOUS, 57436, 'u' },
|
||||
{ KEYC_MEDIA_RECORD, 57437, 'u' },
|
||||
{ KEYC_VOLUME_DOWN, 57438, 'u' },
|
||||
{ KEYC_VOLUME_UP, 57439, 'u' },
|
||||
{ KEYC_VOLUME_MUTE, 57440, 'u' },
|
||||
{ KEYC_LEFT_SHIFT, 57441, 'u' },
|
||||
{ KEYC_LEFT_CTRL, 57442, 'u' },
|
||||
{ KEYC_LEFT_ALT, 57443, 'u' },
|
||||
{ KEYC_LEFT_SUPER, 57444, 'u' },
|
||||
{ KEYC_LEFT_HYPER, 57445, 'u' },
|
||||
{ KEYC_LEFT_META, 57446, 'u' },
|
||||
{ KEYC_RIGHT_SHIFT, 57447, 'u' },
|
||||
{ KEYC_RIGHT_CTRL, 57448, 'u' },
|
||||
{ KEYC_RIGHT_ALT, 57449, 'u' },
|
||||
{ KEYC_RIGHT_SUPER, 57450, 'u' },
|
||||
{ KEYC_RIGHT_HYPER, 57451, 'u' },
|
||||
{ KEYC_RIGHT_META, 57452, 'u' },
|
||||
{ KEYC_ISO_LEVEL3_SHIFT, 57453, 'u' },
|
||||
{ KEYC_ISO_LEVEL5_SHIFT, 57454, 'u' }
|
||||
};
|
||||
|
||||
void
|
||||
input_kitty_reset(struct screen *s)
|
||||
{
|
||||
memset(&s->kitty_keys, 0, sizeof s->kitty_keys);
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_alternate_on(struct screen *s)
|
||||
{
|
||||
s->saved_kitty_keys = s->kitty_keys;
|
||||
input_kitty_reset(s);
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_alternate_off(struct screen *s)
|
||||
{
|
||||
s->kitty_keys = s->saved_kitty_keys;
|
||||
memset(&s->saved_kitty_keys, 0, sizeof s->saved_kitty_keys);
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_set(struct screen *s, u_int flags, int mode)
|
||||
{
|
||||
flags &= KITTY_KEY_SUPPORTED;
|
||||
if (mode == 2)
|
||||
s->kitty_keys.flags |= flags;
|
||||
else if (mode == 3)
|
||||
s->kitty_keys.flags &= ~flags;
|
||||
else
|
||||
s->kitty_keys.flags = flags;
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_push(struct screen *s, u_int flags)
|
||||
{
|
||||
s->kitty_keys.saved_flags = s->kitty_keys.flags;
|
||||
s->kitty_keys.have_saved = 1;
|
||||
s->kitty_keys.flags = flags & KITTY_KEY_SUPPORTED;
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_pop(struct screen *s, u_int count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
if (s->kitty_keys.have_saved && count == 1)
|
||||
s->kitty_keys.flags = s->kitty_keys.saved_flags;
|
||||
else
|
||||
s->kitty_keys.flags = 0;
|
||||
s->kitty_keys.have_saved = 0;
|
||||
}
|
||||
|
||||
static u_int
|
||||
input_kitty_modifiers(key_code key)
|
||||
{
|
||||
u_int modifiers = 1;
|
||||
|
||||
if (key & KEYC_SHIFT)
|
||||
modifiers += 1;
|
||||
if (key & KEYC_META)
|
||||
modifiers += 2;
|
||||
if (key & KEYC_CTRL)
|
||||
modifiers += 4;
|
||||
if (key & KEYC_SUPER)
|
||||
modifiers += 8;
|
||||
if (key & KEYC_HYPER)
|
||||
modifiers += 16;
|
||||
return (modifiers);
|
||||
}
|
||||
|
||||
static const struct input_kitty_key *
|
||||
input_kitty_lookup(key_code key)
|
||||
{
|
||||
key_code lookup;
|
||||
u_int i;
|
||||
|
||||
lookup = key & (KEYC_MASK_KEY|KEYC_KEYPAD);
|
||||
for (i = 0; i < nitems(input_kitty_keys); i++) {
|
||||
if (input_kitty_keys[i].key == lookup)
|
||||
return (&input_kitty_keys[i]);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
input_key_kitty(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
{
|
||||
const struct input_kitty_key *ikk;
|
||||
struct utf8_data ud;
|
||||
wchar_t wc;
|
||||
key_code modifiers, onlykey;
|
||||
u_int flags, number, modifier;
|
||||
char tmp[64];
|
||||
size_t size;
|
||||
|
||||
flags = s->kitty_keys.flags & KITTY_KEY_SUPPORTED;
|
||||
if (flags == 0)
|
||||
return (-1);
|
||||
if ((key & KEYC_MASK_KEY) == KEYC_BTAB)
|
||||
key = C0_HT|(key & ~KEYC_MASK_KEY)|KEYC_SHIFT;
|
||||
|
||||
modifiers = key & (KEYC_SHIFT|KEYC_META|KEYC_CTRL|KEYC_SUPER|KEYC_HYPER);
|
||||
ikk = input_kitty_lookup(key);
|
||||
if (ikk != NULL) {
|
||||
if ((flags & KITTY_KEY_REPORT_ALL) == 0) {
|
||||
if (ikk->key == C0_CR || ikk->key == C0_HT ||
|
||||
ikk->key == KEYC_BSPACE)
|
||||
return (-1);
|
||||
if (ikk->final != 'u' &&
|
||||
(modifiers & (KEYC_SUPER|KEYC_HYPER)) == 0)
|
||||
return (-1);
|
||||
}
|
||||
number = ikk->number;
|
||||
modifier = input_kitty_modifiers(key);
|
||||
if (ikk->final == 'u') {
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%uu", number);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u;%uu",
|
||||
number, modifier);
|
||||
} else if (ikk->final == '~') {
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u~", number);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u;%u~",
|
||||
number, modifier);
|
||||
} else {
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%c",
|
||||
ikk->final);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[1;%u%c",
|
||||
modifier, ikk->final);
|
||||
}
|
||||
goto write;
|
||||
}
|
||||
|
||||
if ((flags & KITTY_KEY_REPORT_ALL) == 0 &&
|
||||
(modifiers & (KEYC_META|KEYC_CTRL|KEYC_SUPER|KEYC_HYPER)) == 0)
|
||||
return (-1);
|
||||
|
||||
onlykey = key & KEYC_MASK_KEY;
|
||||
if (KEYC_IS_UNICODE(key)) {
|
||||
utf8_to_data(onlykey, &ud);
|
||||
if (utf8_towc(&ud, &wc) != UTF8_DONE)
|
||||
return (-1);
|
||||
number = wc;
|
||||
} else if (onlykey <= 0x7f)
|
||||
number = onlykey;
|
||||
else
|
||||
return (-1);
|
||||
if ((key & KEYC_SHIFT) && number >= 'A' && number <= 'Z')
|
||||
number += 'a' - 'A';
|
||||
|
||||
modifier = input_kitty_modifiers(key);
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%uu", number);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u;%uu", number,
|
||||
modifier);
|
||||
|
||||
write:
|
||||
log_debug("%s: %.*s", __func__, (int)size, tmp);
|
||||
bufferevent_write(bev, tmp, size);
|
||||
return (0);
|
||||
}
|
||||
51
input.c
51
input.c
@@ -101,7 +101,6 @@ struct input_ctx {
|
||||
struct bufferevent *event;
|
||||
struct screen_write_ctx ctx;
|
||||
struct colour_palette *palette;
|
||||
struct client *c;
|
||||
|
||||
struct input_cell cell;
|
||||
struct input_cell old_cell;
|
||||
@@ -279,10 +278,6 @@ enum input_csi_type {
|
||||
INPUT_CSI_HPA,
|
||||
INPUT_CSI_ICH,
|
||||
INPUT_CSI_IL,
|
||||
INPUT_CSI_KITTY_POP,
|
||||
INPUT_CSI_KITTY_PUSH,
|
||||
INPUT_CSI_KITTY_QUERY,
|
||||
INPUT_CSI_KITTY_SET,
|
||||
INPUT_CSI_MODOFF,
|
||||
INPUT_CSI_MODSET,
|
||||
INPUT_CSI_QUERY,
|
||||
@@ -348,11 +343,7 @@ static const struct input_table_entry input_csi_table[] = {
|
||||
{ 'r', "", INPUT_CSI_DECSTBM },
|
||||
{ 's', "", INPUT_CSI_SCP },
|
||||
{ 't', "", INPUT_CSI_WINOPS },
|
||||
{ 'u', "", INPUT_CSI_RCP },
|
||||
{ 'u', "<", INPUT_CSI_KITTY_POP },
|
||||
{ 'u', "=", INPUT_CSI_KITTY_SET },
|
||||
{ 'u', ">", INPUT_CSI_KITTY_PUSH },
|
||||
{ 'u', "?", INPUT_CSI_KITTY_QUERY }
|
||||
{ 'u', "", INPUT_CSI_RCP }
|
||||
};
|
||||
|
||||
/* Input transition. */
|
||||
@@ -882,7 +873,7 @@ input_restore_state(struct input_ctx *ictx)
|
||||
/* Initialise input parser. */
|
||||
struct input_ctx *
|
||||
input_init(struct window_pane *wp, struct bufferevent *bev,
|
||||
struct colour_palette *palette, struct client *c)
|
||||
struct colour_palette *palette)
|
||||
{
|
||||
struct input_ctx *ictx;
|
||||
|
||||
@@ -890,7 +881,6 @@ input_init(struct window_pane *wp, struct bufferevent *bev,
|
||||
ictx->wp = wp;
|
||||
ictx->event = bev;
|
||||
ictx->palette = palette;
|
||||
ictx->c = c;
|
||||
|
||||
ictx->input_space = INPUT_BUF_START;
|
||||
ictx->input_buf = xmalloc(INPUT_BUF_START);
|
||||
@@ -1565,33 +1555,6 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
if (options_get_number(global_options, "extended-keys") == 2)
|
||||
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_QUERY:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
input_reply(ictx, 1, "\033[?%uu", s->kitty_keys.flags);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_SET:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
n = input_get(ictx, 0, 0, 0);
|
||||
m = input_get(ictx, 1, 1, 1);
|
||||
if (n >= 0 && m >= 1 && m <= 3)
|
||||
input_kitty_set(s, n, m);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_PUSH:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
n = input_get(ictx, 0, 0, 0);
|
||||
if (n >= 0)
|
||||
input_kitty_push(s, n);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_POP:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
n = input_get(ictx, 0, 1, 1);
|
||||
if (n >= 0)
|
||||
input_kitty_pop(s, n);
|
||||
break;
|
||||
case INPUT_CSI_WINOPS:
|
||||
input_csi_dispatch_winops(ictx);
|
||||
break;
|
||||
@@ -3460,15 +3423,9 @@ input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
return;
|
||||
|
||||
if (wp == NULL) {
|
||||
/* Popup window. */
|
||||
if (ictx->c == NULL) {
|
||||
free(out);
|
||||
return;
|
||||
}
|
||||
tty_set_selection(&ictx->c->tty, clip, out, outlen);
|
||||
paste_add(NULL, out, outlen);
|
||||
free(out);
|
||||
return;
|
||||
} else {
|
||||
/* Normal window. */
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_setselection(&ctx, clip, out, outlen);
|
||||
screen_write_stop(&ctx);
|
||||
|
||||
82
key-string.c
82
key-string.c
@@ -45,29 +45,6 @@ static const struct {
|
||||
{ "F10", KEYC_F10|KEYC_IMPLIED_META },
|
||||
{ "F11", KEYC_F11|KEYC_IMPLIED_META },
|
||||
{ "F12", KEYC_F12|KEYC_IMPLIED_META },
|
||||
{ "F13", KEYC_F13|KEYC_IMPLIED_META },
|
||||
{ "F14", KEYC_F14|KEYC_IMPLIED_META },
|
||||
{ "F15", KEYC_F15|KEYC_IMPLIED_META },
|
||||
{ "F16", KEYC_F16|KEYC_IMPLIED_META },
|
||||
{ "F17", KEYC_F17|KEYC_IMPLIED_META },
|
||||
{ "F18", KEYC_F18|KEYC_IMPLIED_META },
|
||||
{ "F19", KEYC_F19|KEYC_IMPLIED_META },
|
||||
{ "F20", KEYC_F20|KEYC_IMPLIED_META },
|
||||
{ "F21", KEYC_F21|KEYC_IMPLIED_META },
|
||||
{ "F22", KEYC_F22|KEYC_IMPLIED_META },
|
||||
{ "F23", KEYC_F23|KEYC_IMPLIED_META },
|
||||
{ "F24", KEYC_F24|KEYC_IMPLIED_META },
|
||||
{ "F25", KEYC_F25|KEYC_IMPLIED_META },
|
||||
{ "F26", KEYC_F26|KEYC_IMPLIED_META },
|
||||
{ "F27", KEYC_F27|KEYC_IMPLIED_META },
|
||||
{ "F28", KEYC_F28|KEYC_IMPLIED_META },
|
||||
{ "F29", KEYC_F29|KEYC_IMPLIED_META },
|
||||
{ "F30", KEYC_F30|KEYC_IMPLIED_META },
|
||||
{ "F31", KEYC_F31|KEYC_IMPLIED_META },
|
||||
{ "F32", KEYC_F32|KEYC_IMPLIED_META },
|
||||
{ "F33", KEYC_F33|KEYC_IMPLIED_META },
|
||||
{ "F34", KEYC_F34|KEYC_IMPLIED_META },
|
||||
{ "F35", KEYC_F35|KEYC_IMPLIED_META },
|
||||
{ "IC", KEYC_IC|KEYC_IMPLIED_META },
|
||||
{ "Insert", KEYC_IC|KEYC_IMPLIED_META },
|
||||
{ "DC", KEYC_DC|KEYC_IMPLIED_META },
|
||||
@@ -145,54 +122,6 @@ static const struct {
|
||||
{ "KPEnter", KEYC_KP_ENTER|KEYC_KEYPAD },
|
||||
{ "KP0", KEYC_KP_ZERO|KEYC_KEYPAD },
|
||||
{ "KP.", KEYC_KP_PERIOD|KEYC_KEYPAD },
|
||||
{ "KP=", KEYC_KP_EQUAL|KEYC_KEYPAD },
|
||||
{ "KP,", KEYC_KP_SEPARATOR|KEYC_KEYPAD },
|
||||
{ "KPLeft", KEYC_KP_LEFT|KEYC_KEYPAD },
|
||||
{ "KPRight", KEYC_KP_RIGHT|KEYC_KEYPAD },
|
||||
{ "KPUp", KEYC_KP_UP|KEYC_KEYPAD },
|
||||
{ "KPDown", KEYC_KP_DOWN|KEYC_KEYPAD },
|
||||
{ "KPPageUp", KEYC_KP_PPAGE|KEYC_KEYPAD },
|
||||
{ "KPPageDown", KEYC_KP_NPAGE|KEYC_KEYPAD },
|
||||
{ "KPHome", KEYC_KP_HOME|KEYC_KEYPAD },
|
||||
{ "KPEnd", KEYC_KP_END|KEYC_KEYPAD },
|
||||
{ "KPInsert", KEYC_KP_IC|KEYC_KEYPAD },
|
||||
{ "KPDelete", KEYC_KP_DC|KEYC_KEYPAD },
|
||||
{ "KPBegin", KEYC_KP_BEGIN|KEYC_KEYPAD },
|
||||
|
||||
/* Other function keys. */
|
||||
{ "CapsLock", KEYC_CAPSLOCK },
|
||||
{ "ScrollLock", KEYC_SCROLLLOCK },
|
||||
{ "NumLock", KEYC_NUMLOCK },
|
||||
{ "PrintScreen", KEYC_PRINTSCREEN },
|
||||
{ "Pause", KEYC_PAUSE },
|
||||
{ "Menu", KEYC_MENU },
|
||||
{ "MediaPlay", KEYC_MEDIA_PLAY },
|
||||
{ "MediaPause", KEYC_MEDIA_PAUSE },
|
||||
{ "MediaPlayPause", KEYC_MEDIA_PLAYPAUSE },
|
||||
{ "MediaReverse", KEYC_MEDIA_REVERSE },
|
||||
{ "MediaStop", KEYC_MEDIA_STOP },
|
||||
{ "MediaFastForward", KEYC_MEDIA_FASTFORWARD },
|
||||
{ "MediaRewind", KEYC_MEDIA_REWIND },
|
||||
{ "MediaNext", KEYC_MEDIA_NEXT },
|
||||
{ "MediaPrevious", KEYC_MEDIA_PREVIOUS },
|
||||
{ "MediaRecord", KEYC_MEDIA_RECORD },
|
||||
{ "VolumeDown", KEYC_VOLUME_DOWN },
|
||||
{ "VolumeUp", KEYC_VOLUME_UP },
|
||||
{ "VolumeMute", KEYC_VOLUME_MUTE },
|
||||
{ "LeftShift", KEYC_LEFT_SHIFT },
|
||||
{ "LeftControl", KEYC_LEFT_CTRL },
|
||||
{ "LeftAlt", KEYC_LEFT_ALT },
|
||||
{ "LeftSuper", KEYC_LEFT_SUPER },
|
||||
{ "LeftHyper", KEYC_LEFT_HYPER },
|
||||
{ "LeftMeta", KEYC_LEFT_META },
|
||||
{ "RightShift", KEYC_RIGHT_SHIFT },
|
||||
{ "RightControl", KEYC_RIGHT_CTRL },
|
||||
{ "RightAlt", KEYC_RIGHT_ALT },
|
||||
{ "RightSuper", KEYC_RIGHT_SUPER },
|
||||
{ "RightHyper", KEYC_RIGHT_HYPER },
|
||||
{ "RightMeta", KEYC_RIGHT_META },
|
||||
{ "ISOLevel3Shift", KEYC_ISO_LEVEL3_SHIFT },
|
||||
{ "ISOLevel5Shift", KEYC_ISO_LEVEL5_SHIFT },
|
||||
|
||||
/* Mouse keys. */
|
||||
KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
|
||||
@@ -297,13 +226,8 @@ key_string_get_modifiers(const char **string)
|
||||
modifiers |= KEYC_META;
|
||||
break;
|
||||
case 'S':
|
||||
modifiers |= KEYC_SHIFT;
|
||||
break;
|
||||
case 's':
|
||||
modifiers |= KEYC_SUPER;
|
||||
break;
|
||||
case 'H':
|
||||
modifiers |= KEYC_HYPER;
|
||||
modifiers |= KEYC_SHIFT;
|
||||
break;
|
||||
default:
|
||||
*string = NULL;
|
||||
@@ -425,10 +349,6 @@ key_string_lookup_key(key_code key, int with_flags)
|
||||
strlcat(out, "M-", sizeof out);
|
||||
if (key & KEYC_SHIFT)
|
||||
strlcat(out, "S-", sizeof out);
|
||||
if (key & KEYC_SUPER)
|
||||
strlcat(out, "s-", sizeof out);
|
||||
if (key & KEYC_HYPER)
|
||||
strlcat(out, "H-", sizeof out);
|
||||
key &= KEYC_MASK_KEY;
|
||||
|
||||
/* Handle no key. */
|
||||
|
||||
51
layout.c
51
layout.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: layout.c,v 1.100 2026/09/11 08:16:14 nicm Exp $ */
|
||||
/* $OpenBSD: layout.c,v 1.99 2026/09/09 07:03:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -768,49 +768,6 @@ layout_free(struct window *w, int only_nodes)
|
||||
layout_free_cell(w->layout_root, only_nodes);
|
||||
}
|
||||
|
||||
/* Move and resize floating panes so they stay inside the window. */
|
||||
static void
|
||||
layout_clamp_floating_panes(struct window *w, u_int sx, u_int sy)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc;
|
||||
u_int pad, avail, csx, csy;
|
||||
|
||||
TAILQ_FOREACH(wp, &w->z_index, zentry) {
|
||||
lc = wp->layout_cell;
|
||||
if (lc == NULL || (~lc->flags & LAYOUT_CELL_FLOATING))
|
||||
continue;
|
||||
if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
|
||||
pad = 0;
|
||||
else
|
||||
pad = 1;
|
||||
|
||||
csx = lc->g.sx;
|
||||
avail = (sx > 2 * pad) ? sx - 2 * pad : 0;
|
||||
if (csx > avail)
|
||||
csx = (avail > PANE_MINIMUM) ? avail : PANE_MINIMUM;
|
||||
csy = lc->g.sy;
|
||||
avail = (sy > 2 * pad) ? sy - 2 * pad : 0;
|
||||
if (csy > avail)
|
||||
csy = (avail > PANE_MINIMUM) ? avail : PANE_MINIMUM;
|
||||
if (csx != lc->g.sx || csy != lc->g.sy)
|
||||
layout_set_size(lc, csx, csy, lc->g.xoff, lc->g.yoff);
|
||||
|
||||
if (lc->g.xoff + lc->g.sx + pad > sx) {
|
||||
if (lc->g.sx + 2 * pad >= sx)
|
||||
lc->g.xoff = pad;
|
||||
else
|
||||
lc->g.xoff = sx - lc->g.sx - pad;
|
||||
}
|
||||
if (lc->g.yoff + lc->g.sy + pad > sy) {
|
||||
if (lc->g.sy + 2 * pad >= sy)
|
||||
lc->g.yoff = pad;
|
||||
else
|
||||
lc->g.yoff = sy - lc->g.sy - pad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Resize the entire layout after window resize. */
|
||||
void
|
||||
layout_resize(struct window *w, u_int sx, u_int sy)
|
||||
@@ -831,11 +788,8 @@ layout_resize(struct window *w, u_int sx, u_int sy)
|
||||
* out proportionately - this should leave the layout fitting the new
|
||||
* window size.
|
||||
*/
|
||||
if (lc->type == LAYOUT_WINDOWPANE && (lc->flags & LAYOUT_CELL_FLOATING)) {
|
||||
layout_clamp_floating_panes(w, sx, sy);
|
||||
layout_fix_panes(w, NULL);
|
||||
if (lc->type == LAYOUT_WINDOWPANE && (lc->flags & LAYOUT_CELL_FLOATING))
|
||||
return;
|
||||
}
|
||||
xchange = sx - lc->g.sx;
|
||||
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
|
||||
if (xchange < 0 && xchange < -xlimit)
|
||||
@@ -865,7 +819,6 @@ layout_resize(struct window *w, u_int sx, u_int sy)
|
||||
|
||||
/* Fix cell offsets. */
|
||||
layout_fix_offsets(w);
|
||||
layout_clamp_floating_panes(w, sx, sy);
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: options-table.c,v 1.246 2026/09/11 10:17:16 nicm Exp $ */
|
||||
/* $OpenBSD: options-table.c,v 1.245 2026/09/10 11:02:18 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -76,10 +76,9 @@ static const char *options_table_pane_border_indicators_list[] = {
|
||||
"off", "colour", "arrows", "both", NULL
|
||||
};
|
||||
static const char *options_table_pane_border_lines_list[] = {
|
||||
"single", "double", "heavy", "simple", "number", "spaces", "none",
|
||||
"rounded", NULL
|
||||
"single", "double", "heavy", "simple", "number", "spaces", "none", NULL
|
||||
};
|
||||
static const char *options_table_popup_border_lines_list[] = {
|
||||
static const char *options_table_box_lines_list[] = {
|
||||
"single", "double", "heavy", "simple", "rounded", "padded", "none", NULL
|
||||
};
|
||||
static const char *options_table_set_clipboard_list[] = {
|
||||
@@ -104,7 +103,7 @@ static const char *options_table_extended_keys_list[] = {
|
||||
"off", "on", "always", NULL
|
||||
};
|
||||
static const char *options_table_extended_keys_format_list[] = {
|
||||
"csi-u", "xterm", "kitty", NULL
|
||||
"csi-u", "xterm", NULL
|
||||
};
|
||||
static const char *options_table_allow_passthrough_list[] = {
|
||||
"off", "on", "all", NULL
|
||||
@@ -493,7 +492,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "menu-border-lines",
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.choices = options_table_popup_border_lines_list,
|
||||
.choices = options_table_box_lines_list,
|
||||
.default_num = BOX_LINES_SINGLE,
|
||||
.text = "Type of characters used to draw menu border lines. Some of "
|
||||
"these are only supported on terminals with UTF-8 support."
|
||||
@@ -1666,33 +1665,6 @@ const struct options_table_entry options_table[] = {
|
||||
.text = "Pane scrollbar position."
|
||||
},
|
||||
|
||||
{ .name = "popup-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "bg=themedarkgrey,fg=themewhite",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Default style of popups."
|
||||
},
|
||||
|
||||
{ .name = "popup-border-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "bg=themedarkgrey,fg=themelightgrey",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Default style of popup borders."
|
||||
},
|
||||
|
||||
{ .name = "popup-border-lines",
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.choices = options_table_popup_border_lines_list,
|
||||
.default_num = BOX_LINES_SINGLE,
|
||||
.text = "Type of characters used to draw popup border lines. Some of "
|
||||
"these are only supported on terminals with UTF-8 support."
|
||||
},
|
||||
|
||||
{ .name = "remain-on-exit",
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
|
||||
@@ -1400,12 +1400,6 @@ options_push_changes(const char *name)
|
||||
TAILQ_FOREACH(loop, &clients, entry)
|
||||
server_client_set_key_table(loop, NULL);
|
||||
}
|
||||
if (strcmp(name, "extended-keys") == 0) {
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (loop->tty.flags & TTY_STARTED)
|
||||
tty_update_features(&loop->tty);
|
||||
}
|
||||
}
|
||||
if (strcmp(name, "user-keys") == 0) {
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (loop->tty.flags & TTY_OPENED)
|
||||
|
||||
661
popup.c
661
popup.c
@@ -1,661 +0,0 @@
|
||||
/* $OpenBSD: popup.c,v 1.77 2026/08/28 08:02:16 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct popup_data {
|
||||
struct client *c;
|
||||
struct cmdq_item *item;
|
||||
int flags;
|
||||
char *title;
|
||||
|
||||
char *style;
|
||||
char *border_style;
|
||||
struct grid_cell border_cell;
|
||||
enum box_lines border_lines;
|
||||
|
||||
struct screen s;
|
||||
struct grid_cell defaults;
|
||||
struct colour_palette palette;
|
||||
|
||||
struct visible_ranges r;
|
||||
|
||||
struct job *job;
|
||||
struct input_ctx *ictx;
|
||||
int status;
|
||||
popup_close_cb cb;
|
||||
void *arg;
|
||||
|
||||
int close;
|
||||
|
||||
/* Current position and size. */
|
||||
u_int px;
|
||||
u_int py;
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
|
||||
/* Preferred position and size. */
|
||||
u_int ppx;
|
||||
u_int ppy;
|
||||
u_int psx;
|
||||
u_int psy;
|
||||
|
||||
enum { OFF, MOVE, SIZE } dragging;
|
||||
u_int dx;
|
||||
u_int dy;
|
||||
|
||||
u_int lx;
|
||||
u_int ly;
|
||||
u_int lb;
|
||||
};
|
||||
|
||||
static void
|
||||
popup_free(struct popup_data *pd)
|
||||
{
|
||||
server_client_unref(pd->c);
|
||||
|
||||
if (pd->job != NULL)
|
||||
job_free(pd->job);
|
||||
if (pd->ictx != NULL)
|
||||
input_free(pd->ictx);
|
||||
|
||||
free(pd->r.ranges);
|
||||
screen_free(&pd->s);
|
||||
colour_palette_free(&pd->palette);
|
||||
|
||||
free(pd->title);
|
||||
free(pd->style);
|
||||
free(pd->border_style);
|
||||
free(pd);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_reapply_styles(struct popup_data *pd)
|
||||
{
|
||||
struct client *c = pd->c;
|
||||
struct session *s = c->session;
|
||||
struct options *o;
|
||||
struct format_tree *ft;
|
||||
struct style sytmp;
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
o = s->curw->window->options;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, s->curw, NULL);
|
||||
|
||||
/* Reapply popup style from options. */
|
||||
memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults);
|
||||
style_apply(&pd->defaults, o, "popup-style", ft);
|
||||
if (pd->style != NULL) {
|
||||
style_set(&sytmp, &grid_default_cell);
|
||||
if (style_parse(&sytmp, &pd->defaults, pd->style) == 0) {
|
||||
pd->defaults.fg = sytmp.gc.fg;
|
||||
pd->defaults.bg = sytmp.gc.bg;
|
||||
}
|
||||
}
|
||||
pd->defaults.attr = 0;
|
||||
|
||||
/* Reapply border style from options. */
|
||||
memcpy(&pd->border_cell, &grid_default_cell, sizeof pd->border_cell);
|
||||
style_apply(&pd->border_cell, o, "popup-border-style", ft);
|
||||
if (pd->border_style != NULL) {
|
||||
style_set(&sytmp, &grid_default_cell);
|
||||
if (style_parse(&sytmp, &pd->border_cell,
|
||||
pd->border_style) == 0) {
|
||||
pd->border_cell.fg = sytmp.gc.fg;
|
||||
pd->border_cell.bg = sytmp.gc.bg;
|
||||
}
|
||||
}
|
||||
pd->border_cell.attr = 0;
|
||||
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_redraw_cb(const struct tty_ctx *ttyctx)
|
||||
{
|
||||
struct popup_data *pd = ttyctx->arg;
|
||||
|
||||
pd->c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
}
|
||||
|
||||
static int
|
||||
popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
{
|
||||
struct popup_data *pd = ttyctx->arg;
|
||||
|
||||
if (c != pd->c)
|
||||
return (0);
|
||||
if (pd->c->flags & CLIENT_REDRAWOVERLAY)
|
||||
return (0);
|
||||
|
||||
ttyctx->wox = 0;
|
||||
ttyctx->woy = 0;
|
||||
ttyctx->wsx = c->tty.sx;
|
||||
ttyctx->wsy = c->tty.sy;
|
||||
|
||||
if (pd->border_lines == BOX_LINES_NONE) {
|
||||
ttyctx->xoff = ttyctx->rxoff = pd->px;
|
||||
ttyctx->yoff = ttyctx->ryoff = pd->py;
|
||||
} else {
|
||||
ttyctx->xoff = ttyctx->rxoff = pd->px + 1;
|
||||
ttyctx->yoff = ttyctx->ryoff = pd->py + 1;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
|
||||
{
|
||||
struct popup_data *pd = ctx->arg;
|
||||
|
||||
memcpy(&ttyctx->defaults, &pd->defaults, sizeof ttyctx->defaults);
|
||||
ttyctx->flags &= ~TTY_CTX_WINDOW_BIGGER;
|
||||
ttyctx->style_ctx.defaults = &ttyctx->defaults;
|
||||
ttyctx->style_ctx.palette = &pd->palette;
|
||||
ttyctx->redraw_cb = popup_redraw_cb;
|
||||
ttyctx->set_client_cb = popup_set_client_cb;
|
||||
ttyctx->arg = pd;
|
||||
}
|
||||
|
||||
static struct screen *
|
||||
popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy)
|
||||
{
|
||||
struct popup_data *pd = data;
|
||||
|
||||
if (pd->border_lines == BOX_LINES_NONE) {
|
||||
*cx = pd->px + pd->s.cx;
|
||||
*cy = pd->py + pd->s.cy;
|
||||
} else {
|
||||
*cx = pd->px + 1 + pd->s.cx;
|
||||
*cy = pd->py + 1 + pd->s.cy;
|
||||
}
|
||||
return (&pd->s);
|
||||
}
|
||||
|
||||
/* Return parts of the input range which are not obstructed by the popup. */
|
||||
static struct visible_ranges *
|
||||
popup_check_cb(__unused struct client* c, void *data, u_int px, u_int py,
|
||||
u_int nx)
|
||||
{
|
||||
struct popup_data *pd = data;
|
||||
struct visible_ranges *r = &pd->r;
|
||||
|
||||
server_client_overlay_range(pd->px, pd->py, pd->sx, pd->sy, px, py, nx,
|
||||
r);
|
||||
return (r);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_draw_cb(struct client *c, void *data)
|
||||
{
|
||||
struct popup_data *pd = data;
|
||||
struct tty *tty = &c->tty;
|
||||
struct screen s;
|
||||
struct screen_write_ctx ctx;
|
||||
u_int i, px = pd->px, py = pd->py;
|
||||
struct grid_cell defaults;
|
||||
struct tty_style_ctx style_ctx;
|
||||
|
||||
popup_reapply_styles(pd);
|
||||
|
||||
screen_init(&s, pd->sx, pd->sy, 0);
|
||||
if (pd->s.hyperlinks != NULL) {
|
||||
hyperlinks_free(s.hyperlinks);
|
||||
s.hyperlinks = hyperlinks_copy(pd->s.hyperlinks);
|
||||
}
|
||||
screen_write_start(&ctx, &s);
|
||||
screen_write_clearscreen(&ctx, 8);
|
||||
|
||||
if (pd->border_lines == BOX_LINES_NONE) {
|
||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
||||
screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx, pd->sy);
|
||||
} else if (pd->sx > 2 && pd->sy > 2) {
|
||||
screen_write_box(&ctx, pd->sx, pd->sy, pd->border_lines,
|
||||
&pd->border_cell, pd->title);
|
||||
screen_write_cursormove(&ctx, 1, 1, 0);
|
||||
screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2,
|
||||
pd->sy - 2);
|
||||
}
|
||||
screen_write_stop(&ctx);
|
||||
|
||||
memcpy(&defaults, &pd->defaults, sizeof defaults);
|
||||
if (defaults.fg == 8)
|
||||
defaults.fg = pd->palette.fg;
|
||||
if (defaults.bg == 8)
|
||||
defaults.bg = pd->palette.bg;
|
||||
style_ctx.defaults = &defaults;
|
||||
style_ctx.palette = &pd->palette;
|
||||
style_ctx.dim = 0;
|
||||
style_ctx.hyperlinks = s.hyperlinks;
|
||||
|
||||
c->overlay_check = NULL;
|
||||
c->overlay_data = NULL;
|
||||
for (i = 0; i < pd->sy; i++)
|
||||
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &style_ctx);
|
||||
screen_free(&s);
|
||||
c->overlay_check = popup_check_cb;
|
||||
c->overlay_data = pd;
|
||||
}
|
||||
|
||||
static void
|
||||
popup_free_cb(__unused struct client *c, void *data)
|
||||
{
|
||||
struct popup_data *pd = data;
|
||||
struct cmdq_item *item = pd->item;
|
||||
|
||||
if (pd->cb != NULL)
|
||||
pd->cb(pd->status, pd->arg);
|
||||
|
||||
if (item != NULL) {
|
||||
if (cmdq_get_client(item) != NULL &&
|
||||
cmdq_get_client(item)->session == NULL)
|
||||
cmdq_get_client(item)->retval = pd->status;
|
||||
cmdq_continue(item);
|
||||
}
|
||||
|
||||
popup_free(pd);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_resize_cb(__unused struct client *c, void *data)
|
||||
{
|
||||
struct popup_data *pd = data;
|
||||
struct tty *tty = &c->tty;
|
||||
|
||||
if (pd == NULL)
|
||||
return;
|
||||
|
||||
/* Adjust position and size. */
|
||||
if (pd->psy > tty->sy)
|
||||
pd->sy = tty->sy;
|
||||
else
|
||||
pd->sy = pd->psy;
|
||||
if (pd->psx > tty->sx)
|
||||
pd->sx = tty->sx;
|
||||
else
|
||||
pd->sx = pd->psx;
|
||||
if (pd->ppy + pd->sy > tty->sy)
|
||||
pd->py = tty->sy - pd->sy;
|
||||
else
|
||||
pd->py = pd->ppy;
|
||||
if (pd->ppx + pd->sx > tty->sx)
|
||||
pd->px = tty->sx - pd->sx;
|
||||
else
|
||||
pd->px = pd->ppx;
|
||||
|
||||
/* Avoid zero size screens. */
|
||||
if (pd->border_lines == BOX_LINES_NONE) {
|
||||
screen_resize(&pd->s, pd->sx, pd->sy, 0);
|
||||
if (pd->job != NULL)
|
||||
job_resize(pd->job, pd->sx, pd->sy );
|
||||
} else if (pd->sx > 2 && pd->sy > 2) {
|
||||
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 0);
|
||||
if (pd->job != NULL)
|
||||
job_resize(pd->job, pd->sx - 2, pd->sy - 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
popup_handle_drag(struct client *c, struct popup_data *pd,
|
||||
struct mouse_event *m)
|
||||
{
|
||||
u_int px, py;
|
||||
|
||||
if (!MOUSE_DRAG(m->b))
|
||||
pd->dragging = OFF;
|
||||
else if (pd->dragging == MOVE) {
|
||||
if (m->x < pd->dx)
|
||||
px = 0;
|
||||
else if (m->x - pd->dx + pd->sx > c->tty.sx)
|
||||
px = c->tty.sx - pd->sx;
|
||||
else
|
||||
px = m->x - pd->dx;
|
||||
if (m->y < pd->dy)
|
||||
py = 0;
|
||||
else if (m->y - pd->dy + pd->sy > c->tty.sy)
|
||||
py = c->tty.sy - pd->sy;
|
||||
else
|
||||
py = m->y - pd->dy;
|
||||
pd->px = px;
|
||||
pd->py = py;
|
||||
pd->dx = m->x - pd->px;
|
||||
pd->dy = m->y - pd->py;
|
||||
pd->ppx = px;
|
||||
pd->ppy = py;
|
||||
server_redraw_client(c);
|
||||
} else if (pd->dragging == SIZE) {
|
||||
if (pd->border_lines == BOX_LINES_NONE) {
|
||||
if (m->x < pd->px + 1)
|
||||
return;
|
||||
if (m->y < pd->py + 1)
|
||||
return;
|
||||
} else {
|
||||
if (m->x < pd->px + 3)
|
||||
return;
|
||||
if (m->y < pd->py + 3)
|
||||
return;
|
||||
}
|
||||
pd->sx = m->x - pd->px;
|
||||
pd->sy = m->y - pd->py;
|
||||
pd->psx = pd->sx;
|
||||
pd->psy = pd->sy;
|
||||
|
||||
if (pd->border_lines == BOX_LINES_NONE) {
|
||||
screen_resize(&pd->s, pd->sx, pd->sy, 0);
|
||||
if (pd->job != NULL)
|
||||
job_resize(pd->job, pd->sx, pd->sy);
|
||||
} else {
|
||||
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 0);
|
||||
if (pd->job != NULL)
|
||||
job_resize(pd->job, pd->sx - 2, pd->sy - 2);
|
||||
}
|
||||
server_redraw_client(c);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
popup_key_cb(struct client *c, void *data, struct key_event *event)
|
||||
{
|
||||
struct popup_data *pd = data;
|
||||
struct mouse_event *m = &event->m;
|
||||
const char *buf;
|
||||
size_t len;
|
||||
u_int px, py;
|
||||
enum { NONE, LEFT, RIGHT, TOP, BOTTOM } border = NONE;
|
||||
|
||||
if (KEYC_IS_MOUSE(event->key)) {
|
||||
if (pd->dragging != OFF) {
|
||||
popup_handle_drag(c, pd, m);
|
||||
goto out;
|
||||
}
|
||||
if (m->x < pd->px ||
|
||||
m->x > pd->px + pd->sx - 1 ||
|
||||
m->y < pd->py ||
|
||||
m->y > pd->py + pd->sy - 1) {
|
||||
return (0);
|
||||
}
|
||||
if (pd->border_lines != BOX_LINES_NONE) {
|
||||
if (m->x == pd->px)
|
||||
border = LEFT;
|
||||
else if (m->x == pd->px + pd->sx - 1)
|
||||
border = RIGHT;
|
||||
else if (m->y == pd->py)
|
||||
border = TOP;
|
||||
else if (m->y == pd->py + pd->sy - 1)
|
||||
border = BOTTOM;
|
||||
}
|
||||
if ((m->b & MOUSE_MASK_MODIFIERS) == 0 &&
|
||||
MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3 &&
|
||||
(border == LEFT || border == TOP))
|
||||
goto out;
|
||||
if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) ||
|
||||
(border != NONE && !MOUSE_DRAG(m->lb))) {
|
||||
if (!MOUSE_DRAG(m->b))
|
||||
goto out;
|
||||
if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_1)
|
||||
pd->dragging = MOVE;
|
||||
else if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_3)
|
||||
pd->dragging = SIZE;
|
||||
pd->dx = m->lx - pd->px;
|
||||
pd->dy = m->ly - pd->py;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) ||
|
||||
pd->job == NULL) &&
|
||||
(event->key == '\033' || event->key == ('c'|KEYC_CTRL)))
|
||||
return (1);
|
||||
if (pd->job == NULL && (pd->flags & POPUP_CLOSEANYKEY) &&
|
||||
!KEYC_IS_MOUSE(event->key) && !KEYC_IS_PASTE(event->key))
|
||||
return (1);
|
||||
if (pd->job != NULL) {
|
||||
if (KEYC_IS_MOUSE(event->key)) {
|
||||
/* Must be inside, checked already. */
|
||||
if (pd->border_lines == BOX_LINES_NONE) {
|
||||
px = m->x - pd->px;
|
||||
py = m->y - pd->py;
|
||||
} else {
|
||||
px = m->x - pd->px - 1;
|
||||
py = m->y - pd->py - 1;
|
||||
}
|
||||
if (!input_key_get_mouse(&pd->s, m, px, py, &buf, &len))
|
||||
return (0);
|
||||
bufferevent_write(job_get_event(pd->job), buf, len);
|
||||
return (0);
|
||||
}
|
||||
input_key(&pd->s, job_get_event(pd->job), event->key);
|
||||
}
|
||||
return (0);
|
||||
|
||||
out:
|
||||
pd->lx = m->x;
|
||||
pd->ly = m->y;
|
||||
pd->lb = m->b;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_job_update_cb(struct job *job)
|
||||
{
|
||||
struct popup_data *pd = job_get_data(job);
|
||||
struct evbuffer *evb = job_get_event(job)->input;
|
||||
struct client *c = pd->c;
|
||||
struct screen *s = &pd->s;
|
||||
void *data = EVBUFFER_DATA(evb);
|
||||
size_t size = EVBUFFER_LENGTH(evb);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
c->overlay_check = NULL;
|
||||
c->overlay_data = NULL;
|
||||
input_parse_screen(pd->ictx, s, popup_init_ctx_cb, pd, data, size);
|
||||
c->overlay_check = popup_check_cb;
|
||||
c->overlay_data = pd;
|
||||
|
||||
evbuffer_drain(evb, size);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_job_complete_cb(struct job *job)
|
||||
{
|
||||
struct popup_data *pd = job_get_data(job);
|
||||
int status;
|
||||
|
||||
status = job_get_status(pd->job);
|
||||
if (WIFEXITED(status))
|
||||
pd->status = WEXITSTATUS(status);
|
||||
else if (WIFSIGNALED(status))
|
||||
pd->status = WTERMSIG(status);
|
||||
else
|
||||
pd->status = 0;
|
||||
pd->job = NULL;
|
||||
|
||||
if ((pd->flags & POPUP_CLOSEEXIT) ||
|
||||
((pd->flags & POPUP_CLOSEEXITZERO) && pd->status == 0))
|
||||
server_client_clear_overlay(pd->c);
|
||||
}
|
||||
|
||||
int
|
||||
popup_present(struct client *c)
|
||||
{
|
||||
return (c->overlay_draw == popup_draw_cb);
|
||||
}
|
||||
|
||||
int
|
||||
popup_modify(struct client *c, const char *title, const char *style,
|
||||
const char *border_style, enum box_lines lines, int flags)
|
||||
{
|
||||
struct popup_data *pd = c->overlay_data;
|
||||
struct style sytmp;
|
||||
|
||||
if (title != NULL) {
|
||||
if (pd->title != NULL)
|
||||
free(pd->title);
|
||||
pd->title = xstrdup(title);
|
||||
}
|
||||
if (border_style != NULL) {
|
||||
free(pd->border_style);
|
||||
pd->border_style = xstrdup(border_style);
|
||||
style_set(&sytmp, &pd->border_cell);
|
||||
if (style_parse(&sytmp, &pd->border_cell, border_style) == 0) {
|
||||
pd->border_cell.fg = sytmp.gc.fg;
|
||||
pd->border_cell.bg = sytmp.gc.bg;
|
||||
}
|
||||
}
|
||||
if (style != NULL) {
|
||||
free(pd->style);
|
||||
pd->style = xstrdup(style);
|
||||
style_set(&sytmp, &pd->defaults);
|
||||
if (style_parse(&sytmp, &pd->defaults, style) == 0) {
|
||||
pd->defaults.fg = sytmp.gc.fg;
|
||||
pd->defaults.bg = sytmp.gc.bg;
|
||||
}
|
||||
}
|
||||
if (lines != BOX_LINES_DEFAULT) {
|
||||
if (lines == BOX_LINES_NONE && pd->border_lines != lines) {
|
||||
screen_resize(&pd->s, pd->sx, pd->sy, 1);
|
||||
job_resize(pd->job, pd->sx, pd->sy);
|
||||
} else if (pd->border_lines == BOX_LINES_NONE &&
|
||||
pd->border_lines != lines) {
|
||||
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 1);
|
||||
job_resize(pd->job, pd->sx - 2, pd->sy - 2);
|
||||
}
|
||||
pd->border_lines = lines;
|
||||
tty_resize(&c->tty);
|
||||
}
|
||||
if (flags != -1)
|
||||
pd->flags = flags;
|
||||
|
||||
server_redraw_client(c);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
||||
u_int py, u_int sx, u_int sy, struct environ *env, const char *shellcmd,
|
||||
int argc, char **argv, const char *cwd, const char *title, struct client *c,
|
||||
struct session *s, const char *style, const char *border_style,
|
||||
popup_close_cb cb, void *arg)
|
||||
{
|
||||
struct popup_data *pd;
|
||||
u_int jx, jy;
|
||||
struct options *o;
|
||||
struct style sytmp;
|
||||
|
||||
if (s != NULL)
|
||||
o = s->curw->window->options;
|
||||
else
|
||||
o = c->session->curw->window->options;
|
||||
|
||||
if (lines == BOX_LINES_DEFAULT)
|
||||
lines = options_get_number(o, "popup-border-lines");
|
||||
if (lines == BOX_LINES_NONE) {
|
||||
if (sx < 1 || sy < 1)
|
||||
return (-1);
|
||||
jx = sx;
|
||||
jy = sy;
|
||||
} else {
|
||||
if (sx < 3 || sy < 3)
|
||||
return (-1);
|
||||
jx = sx - 2;
|
||||
jy = sy - 2;
|
||||
}
|
||||
if (c->tty.sx < sx || c->tty.sy < sy)
|
||||
return (-1);
|
||||
|
||||
pd = xcalloc(1, sizeof *pd);
|
||||
pd->item = item;
|
||||
pd->flags = flags;
|
||||
|
||||
if (title != NULL)
|
||||
pd->title = xstrdup(title);
|
||||
if (style != NULL)
|
||||
pd->style = xstrdup(style);
|
||||
if (border_style != NULL)
|
||||
pd->border_style = xstrdup(border_style);
|
||||
|
||||
pd->c = c;
|
||||
pd->c->references++;
|
||||
|
||||
pd->cb = cb;
|
||||
pd->arg = arg;
|
||||
pd->status = 128 + SIGHUP;
|
||||
|
||||
pd->border_lines = lines;
|
||||
memcpy(&pd->border_cell, &grid_default_cell, sizeof pd->border_cell);
|
||||
style_apply(&pd->border_cell, o, "popup-border-style", NULL);
|
||||
if (border_style != NULL) {
|
||||
style_set(&sytmp, &grid_default_cell);
|
||||
if (style_parse(&sytmp, &pd->border_cell, border_style) == 0) {
|
||||
pd->border_cell.fg = sytmp.gc.fg;
|
||||
pd->border_cell.bg = sytmp.gc.bg;
|
||||
}
|
||||
}
|
||||
pd->border_cell.attr = 0;
|
||||
|
||||
screen_init(&pd->s, jx, jy, 0);
|
||||
screen_set_default_cursor(&pd->s, global_w_options);
|
||||
colour_palette_init(&pd->palette);
|
||||
colour_palette_from_option(&pd->palette, global_w_options);
|
||||
|
||||
memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults);
|
||||
style_apply(&pd->defaults, o, "popup-style", NULL);
|
||||
if (style != NULL) {
|
||||
style_set(&sytmp, &grid_default_cell);
|
||||
if (style_parse(&sytmp, &pd->defaults, style) == 0) {
|
||||
pd->defaults.fg = sytmp.gc.fg;
|
||||
pd->defaults.bg = sytmp.gc.bg;
|
||||
}
|
||||
}
|
||||
pd->defaults.attr = 0;
|
||||
|
||||
pd->px = px;
|
||||
pd->py = py;
|
||||
pd->sx = sx;
|
||||
pd->sy = sy;
|
||||
|
||||
pd->ppx = px;
|
||||
pd->ppy = py;
|
||||
pd->psx = sx;
|
||||
pd->psy = sy;
|
||||
|
||||
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
|
||||
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
|
||||
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
|
||||
if (pd->job == NULL) {
|
||||
popup_free(pd);
|
||||
return (-1);
|
||||
}
|
||||
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette, c);
|
||||
|
||||
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
||||
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
|
||||
return (0);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Popups require a tty overlay and cannot be displayed by a control client.
|
||||
# Popups require an attached terminal and cannot be displayed by a control
|
||||
# client.
|
||||
# A popup command from control mode must be ignored cleanly, leaving the
|
||||
# client command queue and server usable.
|
||||
|
||||
|
||||
@@ -268,149 +268,5 @@ $TMUX kill-pane -t "$floating" || exit 1
|
||||
$TMUX kill-pane -t "$right" || exit 1
|
||||
$TMUX kill-pane -t "$lower" || exit 1
|
||||
|
||||
# --- Floating panes clamped when the window shrinks (issue #5581, PR #5582) ---
|
||||
#
|
||||
# layout_resize clamps floating panes back inside the window when it shrinks:
|
||||
# move them and, only if they cannot fit, shrink them (never below
|
||||
# PANE_MINIMUM). A floating cell is the pane's content, so with the default
|
||||
# single-line border the clamp counts 1 cell of border per side, exactly as
|
||||
# layout_floating_args_parse does on creation; with no border it counts 0.
|
||||
# Each case below gets its own window, since resize-window fixes a window at
|
||||
# a manual size for the rest of its life.
|
||||
|
||||
# Case 1: a lone floating pane -- break-pane -W on a window's only pane --
|
||||
# takes the early-return path in layout_resize, added during PR #5582's
|
||||
# review round, since there is no tiled tree to walk.
|
||||
win=$($TMUX new-window -dPF '#{window_id}') ||
|
||||
fail "new-window for lone float failed"
|
||||
|
||||
# -x 20 -y 6 -> pane 18x4; -X 60 -Y 18 -> pane_left 61, pane_top 19: with the
|
||||
# border, the footprint is columns 60-79, rows 18-23, flush with the 80x24
|
||||
# window's right and bottom edges, so the float fits before it is shrunk.
|
||||
$TMUX break-pane -W -s "$win" -x 20 -y 6 -X 60 -Y 18 ||
|
||||
fail "break-pane -W for lone float failed"
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_width}')" 18
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_height}')" 4
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_left}')" 61
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_top}')" 19
|
||||
|
||||
# Shrink to 40x16. The float still fits at its own size (18 <= 40-2, 4 <=
|
||||
# 16-2) so only its position moves, flush to the new right/bottom edges:
|
||||
# xoff = 40 - 18 - 1 = 21; yoff = 16 - 4 - 1 = 11.
|
||||
$TMUX resize-window -t "$win" -x 40 -y 16 ||
|
||||
fail "resize-window (lone float) failed"
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_width}')" 18
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_height}')" 4
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_left}')" 21
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_top}')" 11
|
||||
|
||||
# Case 5: grow the window back. The clamp must not chase the window back
|
||||
# outward -- it only ever pulls a float in, never restores where it was.
|
||||
$TMUX resize-window -t "$win" -x 80 -y 24 ||
|
||||
fail "resize-window grow (lone float) failed"
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_width}')" 18
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_height}')" 4
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_left}')" 21
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_top}')" 11
|
||||
$TMUX kill-window -t "$win" || exit 1
|
||||
|
||||
# Case 2: the same float, but with a tiled sibling surviving alongside it, so
|
||||
# the window's root cell stays tiled and layout_resize takes the normal path
|
||||
# (the clamp call after layout_fix_offsets) instead of the early return
|
||||
# above. Same geometry as case 1, so the same numbers should come out.
|
||||
win=$($TMUX new-window -dPF '#{window_id}') ||
|
||||
fail "new-window for tiled sibling failed"
|
||||
$TMUX split-window -t "$win" 'sleep 100' ||
|
||||
fail "split-window for tiled sibling failed"
|
||||
$TMUX break-pane -W -s "$win" -x 20 -y 6 -X 60 -Y 18 ||
|
||||
fail "break-pane -W for tiled sibling failed"
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_width}')" 18
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_height}')" 4
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_left}')" 61
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_top}')" 19
|
||||
|
||||
$TMUX resize-window -t "$win" -x 40 -y 16 ||
|
||||
fail "resize-window (tiled sibling) failed"
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_width}')" 18
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_height}')" 4
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_left}')" 21
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_top}')" 11
|
||||
$TMUX kill-window -t "$win" || exit 1
|
||||
|
||||
# Case 3: new-pane float, the original repro from issue #5581 and the PR
|
||||
# body -- also the normal path, via the tiled base pane new-window creates.
|
||||
win=$($TMUX new-window -dPF '#{window_id}') ||
|
||||
fail "new-window for new-pane repro failed"
|
||||
$TMUX resize-window -t "$win" -x 120 -y 40 ||
|
||||
fail "resize-window to 120x40 failed"
|
||||
|
||||
# -x 30 -y 10 -> pane 28x8; -X 85 -Y 25 -> pane_left 86, pane_top 26.
|
||||
floating=$($TMUX new-pane -t "$win" -dPF '#{pane_id}' \
|
||||
-x 30 -y 10 -X 85 -Y 25 'sleep 100') ||
|
||||
fail "new-pane for new-pane repro failed"
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_width}')" 28
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_left}')" 86
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_top}')" 26
|
||||
|
||||
# Shrink to 60x20: xoff = 60 - 28 - 1 = 31; yoff = 20 - 8 - 1 = 11.
|
||||
$TMUX resize-window -t "$win" -x 60 -y 20 ||
|
||||
fail "resize-window (new-pane repro) failed"
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_width}')" 28
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_left}')" 31
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_top}')" 11
|
||||
$TMUX kill-window -t "$win" || exit 1
|
||||
|
||||
# Case 4: a float that already fits inside the shrunk window is left alone --
|
||||
# assert position and size are both unchanged, not just one of them.
|
||||
win=$($TMUX new-window -dPF '#{window_id}') ||
|
||||
fail "new-window for untouched float failed"
|
||||
|
||||
# -x 20 -y 6 -> pane 18x4; -X 8 -Y 3 -> pane_left 9, pane_top 4 (as at the top
|
||||
# of this file). Footprint columns 8-27, rows 3-8: well inside 60x20 too.
|
||||
floating=$($TMUX new-pane -t "$win" -dPF '#{pane_id}' \
|
||||
-x 20 -y 6 -X 8 -Y 3 'sleep 100') ||
|
||||
fail "new-pane for untouched float failed"
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_width}')" 18
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 4
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_left}')" 9
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_top}')" 4
|
||||
|
||||
$TMUX resize-window -t "$win" -x 60 -y 20 ||
|
||||
fail "resize-window (untouched float) failed"
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_width}')" 18
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 4
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_left}')" 9
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_top}')" 4
|
||||
$TMUX kill-window -t "$win" || exit 1
|
||||
|
||||
# Case 6: pad = 0, via the pane-border-lines window option set to none. The
|
||||
# border arithmetic differs here (no -2/+1 adjustment either on creation or
|
||||
# in the clamp).
|
||||
win=$($TMUX new-window -dPF '#{window_id}') ||
|
||||
fail "new-window for pad=0 float failed"
|
||||
$TMUX set-option -w -t "$win" pane-border-lines none ||
|
||||
fail "set pane-border-lines none failed"
|
||||
|
||||
# No border: -x 20 -y 6 -> pane 20x6 directly; -X 60 -Y 18 -> pane_left 60,
|
||||
# pane_top 18 directly. Footprint (== content, no border) is columns 60-79,
|
||||
# rows 18-23: flush right/bottom of the 80x24 window, same as case 1.
|
||||
$TMUX break-pane -W -s "$win" -x 20 -y 6 -X 60 -Y 18 ||
|
||||
fail "break-pane -W for pad=0 float failed"
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_width}')" 20
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_height}')" 6
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_left}')" 60
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_top}')" 18
|
||||
|
||||
# Shrink to 40x16 with pad=0: xoff = 40 - 20 - 0 = 20; yoff = 16 - 6 - 0 = 10.
|
||||
$TMUX resize-window -t "$win" -x 40 -y 16 ||
|
||||
fail "resize-window (pad=0 float) failed"
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_width}')" 20
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_height}')" 6
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_left}')" 20
|
||||
must_equal "$($TMUX display-message -p -t "$win" '#{pane_top}')" 10
|
||||
$TMUX kill-window -t "$win" || exit 1
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test per-client keyboard protocol detection and pane-side encoding.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
KCONF=$(mktemp)
|
||||
LCONF=$(mktemp)
|
||||
OUT=$(mktemp)
|
||||
TMP=$(mktemp)
|
||||
SOCKETS="testKmc$$ testKka$$ testKua$$ testKrt$$ testKru$$ testKlq$$ testKlu$$"
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' >"$KCONF"
|
||||
printf '%s\n' 'set -g extended-keys off' >"$LCONF"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -f "$KCONF" "$LCONF" "$OUT" "$TMP"
|
||||
for socket in $SOCKETS; do
|
||||
$TEST_TMUX -L"$socket" kill-server 2>/dev/null
|
||||
done
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
wait_for_mode()
|
||||
{
|
||||
tmux=$1
|
||||
wanted=$2
|
||||
i=0
|
||||
while [ "$($tmux display-message -pt: '#{pane_key_mode}')" != "$wanted" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($tmux display-message -pt: '#{pane_key_mode}')" = "$wanted" ]
|
||||
}
|
||||
|
||||
wait_for_output()
|
||||
{
|
||||
i=0
|
||||
while [ ! -s "$1" ] && [ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ -s "$1" ]
|
||||
}
|
||||
|
||||
client_mode()
|
||||
{
|
||||
tmux=$1
|
||||
session=$2
|
||||
|
||||
if [ -z "$session" ]; then
|
||||
$tmux list-clients -F '#{client_key_mode}'
|
||||
else
|
||||
$tmux list-clients -F '#{client_session}:#{client_key_mode}' |
|
||||
sed -n "s/^$session://p"
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_client_mode()
|
||||
{
|
||||
tmux=$1
|
||||
session=$2
|
||||
wanted=$3
|
||||
i=0
|
||||
while [ "$(client_mode "$tmux" "$session")" != "$wanted" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$(client_mode "$tmux" "$session")" = "$wanted" ]
|
||||
}
|
||||
|
||||
# Each client must be negotiated independently. A tmux with extended-keys off
|
||||
# stands in for a terminal without Kitty keys, since it does not answer the
|
||||
# query.
|
||||
M="$TEST_TMUX -LtestKmc$$ -f$KCONF"
|
||||
KA="$TEST_TMUX -LtestKka$$ -f$KCONF"
|
||||
UA="$TEST_TMUX -LtestKua$$ -f$LCONF"
|
||||
$M new-session -d -x80 -y24 -s kitty || exit 1
|
||||
$M new-session -d -x80 -y24 -s csiu || exit 1
|
||||
$KA new-session -d -x80 -y24 "$M attach-session -t kitty" || exit 1
|
||||
$UA new-session -d -x80 -y24 "$M attach-session -t csiu" || exit 1
|
||||
wait_for_mode "$KA" 'Kitty 1' || exit 1
|
||||
|
||||
# Each client must report the protocol its own terminal negotiated.
|
||||
wait_for_client_mode "$M" kitty 'Kitty 1' || exit 1
|
||||
wait_for_client_mode "$M" csiu 'Ext' || exit 1
|
||||
|
||||
uc=$($M list-clients -F '#{client_name} #{client_session}' |
|
||||
awk '$2 == "csiu" { print $1 }')
|
||||
[ -n "$uc" ] || exit 1
|
||||
$M command-prompt -t"$uc" -k 'display-message -pl "%%"' >"$TMP" &
|
||||
pid=$!
|
||||
sleep 0.2
|
||||
$UA send-keys Escape '[97;5u'
|
||||
wait "$pid"
|
||||
[ "$(tr -d '[:space:]' <"$TMP")" = 'C-a' ] || exit 1
|
||||
|
||||
# A Kitty-capable terminal must still be reported when it is not in use.
|
||||
$M set-option -g extended-keys off
|
||||
wait_for_client_mode "$M" kitty 'VT10x (Kitty)' || exit 1
|
||||
wait_for_client_mode "$M" csiu 'VT10x' || exit 1
|
||||
$M set-option -g extended-keys on
|
||||
wait_for_client_mode "$M" kitty 'Kitty 1' || exit 1
|
||||
|
||||
$KA kill-server 2>/dev/null
|
||||
$UA kill-server 2>/dev/null
|
||||
$M kill-server 2>/dev/null
|
||||
|
||||
# Standard extended input must be translated for a Kitty-requesting pane.
|
||||
: >"$OUT"
|
||||
R="$TEST_TMUX -LtestKrt$$ -f$KCONF"
|
||||
RU="$TEST_TMUX -LtestKru$$ -f$LCONF"
|
||||
$R new-session -d -x80 -y24 \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5" || exit 1
|
||||
$RU new-session -d -x80 -y24 "$R attach-session" || exit 1
|
||||
wait_for_client_mode "$R" '' 'Ext' || exit 1
|
||||
$RU send-keys C-a
|
||||
wait_for_output "$OUT" || exit 1
|
||||
[ "$(tr -d ' \n' <"$OUT")" = '1b5b39373b3575' ] || exit 1
|
||||
$RU kill-server 2>/dev/null
|
||||
$R kill-server 2>/dev/null
|
||||
|
||||
# An application is told the Kitty flags it asked for even when a client that
|
||||
# only supports VT10x is attached, and keys from that client are encoded as it
|
||||
# asked.
|
||||
: >"$OUT"
|
||||
: >"$TMP"
|
||||
printf '%s\n' "set -as terminal-overrides ',*:Eneks@:Dseks@'" >>"$KCONF"
|
||||
LQ="$TEST_TMUX -LtestKlq$$ -f$KCONF"
|
||||
LU="$TEST_TMUX -LtestKlu$$ -f$LCONF"
|
||||
$LQ new-session -d -x80 -y24 \
|
||||
"stty raw -echo; sleep 2; printf '\033[>1u\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$TMP'; sleep 5" || exit 1
|
||||
$LU new-session -d -x80 -y24 "$LQ attach-session" || exit 1
|
||||
wait_for_output "$OUT" || exit 1
|
||||
[ "$(tr -d ' \n' <"$OUT")" = '1b5b3f3175' ] || exit 1
|
||||
wait_for_client_mode "$LQ" '' 'VT10x' || exit 1
|
||||
$LU send-keys C-a
|
||||
wait_for_output "$TMP" || exit 1
|
||||
[ "$(tr -d ' \n' <"$TMP")" = '1b5b39373b3575' ] || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -1,116 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test client-side Kitty keyboard protocol support: an outer tmux acts as a
|
||||
# Kitty-capable terminal for the inner tmux which is the one under test. The
|
||||
# inner tmux queries the outer one, the outer one replies, and the inner one
|
||||
# then parses the key sequences sent to it.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
CONF=$(mktemp)
|
||||
TMP=$(mktemp)
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' >"$CONF"
|
||||
|
||||
TMUX="$TEST_TMUX -LtestKIA$$ -f$CONF"
|
||||
TMUX2="$TEST_TMUX -LtestKIB$$ -f$CONF"
|
||||
|
||||
trap 'rm -f "$CONF" "$TMP"; $TMUX kill-server 2>/dev/null; \
|
||||
$TMUX2 kill-server 2>/dev/null' 0 1 15
|
||||
|
||||
$TMUX2 new-session -d -x80 -y24 || exit 1
|
||||
$TMUX new-session -d -x80 -y24 "$TMUX2 attach" || exit 1
|
||||
|
||||
exit_status=0
|
||||
|
||||
wait_for_mode()
|
||||
{
|
||||
i=0
|
||||
while [ "$($TMUX display-message -pt: '#{pane_key_mode}')" != "$1" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($TMUX display-message -pt: '#{pane_key_mode}')" = "$1" ]
|
||||
}
|
||||
|
||||
assert_key()
|
||||
{
|
||||
keys=$1
|
||||
expected=$2
|
||||
|
||||
$TMUX2 command-prompt -k 'display-message -pl "%%"' >"$TMP" &
|
||||
sleep 0.15
|
||||
# Send raw bytes so the outer tmux does not encode them itself.
|
||||
raw=$(printf '%s' "$keys" | sed -e 's/Escape /\\033/g' -e 's/ //g')
|
||||
$TMUX send-keys -H $(printf "$raw" | od -An -v -t x1)
|
||||
wait
|
||||
|
||||
actual=$(tr -d '[:space:]' <"$TMP")
|
||||
if [ "$actual" = "$expected" ]; then
|
||||
[ -n "$VERBOSE" ] && echo "[PASS] $keys -> $actual"
|
||||
else
|
||||
echo "[FAIL] $keys -> $expected (got '$actual')"
|
||||
exit_status=1
|
||||
fi
|
||||
}
|
||||
|
||||
# The inner tmux must detect the outer one and push its flags.
|
||||
if ! wait_for_mode 'Kitty 1'; then
|
||||
echo "[FAIL] inner tmux did not enable the Kitty protocol"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Modifiers, including the Kitty-only Super and Hyper.
|
||||
assert_key 'Escape [97;2u' 'S-a'
|
||||
assert_key 'Escape [97;3u' 'M-a'
|
||||
assert_key 'Escape [97;5u' 'C-a'
|
||||
assert_key 'Escape [97;6u' 'C-S-a'
|
||||
assert_key 'Escape [97;7u' 'C-M-a'
|
||||
assert_key 'Escape [97;9u' 's-a'
|
||||
assert_key 'Escape [97;17u' 'H-a'
|
||||
assert_key 'Escape [65;2u' 'S-A'
|
||||
|
||||
# Keys with a dedicated tmux key code.
|
||||
assert_key 'Escape [9;5u' 'C-Tab'
|
||||
assert_key 'Escape [9;2u' 'BTab'
|
||||
assert_key 'Escape [13;5u' 'C-Enter'
|
||||
assert_key 'Escape [27u' 'Escape'
|
||||
assert_key 'Escape [32;5u' 'C-Space'
|
||||
assert_key 'Escape [127;5u' 'C-BSpace'
|
||||
|
||||
# Keys with a CSI final byte other than u.
|
||||
assert_key 'Escape [1;5A' 'C-Up'
|
||||
assert_key 'Escape [1;3D' 'M-Left'
|
||||
assert_key 'Escape [1;5H' 'C-Home'
|
||||
assert_key 'Escape [1;5P' 'C-F1'
|
||||
|
||||
# Functional and non-ASCII keys.
|
||||
assert_key 'Escape [57399;5u' 'C-KP0'
|
||||
assert_key 'Escape [233;5u' 'C-é'
|
||||
|
||||
# The alternate key and associated text fields are not requested but must be
|
||||
# ignored if a terminal sends them anyway.
|
||||
assert_key 'Escape [97:65;2u' 'S-a'
|
||||
assert_key 'Escape [97:65:97;5u' 'C-a'
|
||||
assert_key 'Escape [97;5;97u' 'C-a'
|
||||
|
||||
# A repeat event is a key press, a release event is dropped. The C-b that
|
||||
# follows shows that the sequence was consumed and not passed through.
|
||||
assert_key 'Escape [97;5:1u' 'C-a'
|
||||
assert_key 'Escape [97;5:2u' 'C-a'
|
||||
assert_key 'Escape [97;5:3u Escape [98;5u' 'C-b'
|
||||
|
||||
# The Meta modifier bit is not representable and is dropped.
|
||||
assert_key 'Escape [97;33u Escape [98;5u' 'C-b'
|
||||
|
||||
# Lock modifiers are ignored rather than dropping the key.
|
||||
assert_key 'Escape [97;65u' 'a'
|
||||
assert_key 'Escape [97;129u' 'a'
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
exit $exit_status
|
||||
@@ -1,85 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test the Kitty keyboard protocol against a real terminal rather than against
|
||||
# another copy of tmux. This drives kitty through its remote control interface
|
||||
# so that kitty itself encodes the key presses.
|
||||
#
|
||||
# This has to be run by hand from this directory. The Makefile runs tests with
|
||||
# env -i, which removes DISPLAY and HOME, so kitty cannot start and this exits
|
||||
# immediately without testing anything. It is also skipped unless kitty is
|
||||
# installed and is new enough to have send-key.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
command -v kitty >/dev/null 2>&1 || exit 0
|
||||
[ -n "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ] || exit 0
|
||||
kitty @ --help 2>/dev/null | grep -q 'send-key' || exit 0
|
||||
|
||||
DIR=$(mktemp -d)
|
||||
CONF=$DIR/conf
|
||||
SOCKET=$DIR/kitty
|
||||
OUT=$DIR/out
|
||||
TMUX="$TEST_TMUX -LtestKrt$$ -f$CONF"
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' \
|
||||
'set -g extended-keys-format kitty' >"$CONF"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
rm -rf "$DIR"
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
kitty -o allow_remote_control=yes --listen-on "unix:$SOCKET" \
|
||||
-o confirm_os_window_close=0 -e \
|
||||
$TMUX new-session -s r "sleep 120" >"$DIR/err" 2>&1 &
|
||||
|
||||
# The terminfo entry for kitty may be missing, so treat a server which never
|
||||
# appears as a reason to skip rather than as a failure.
|
||||
i=0
|
||||
while ! $TMUX has-session -t r 2>/dev/null && [ "$i" -lt 150 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
$TMUX has-session -t r 2>/dev/null || exit 0
|
||||
|
||||
# The client must negotiate the protocol with the real terminal.
|
||||
i=0
|
||||
while [ "$($TMUX list-clients -F '#{client_key_mode}')" != 'Kitty 1' ] &&
|
||||
[ "$i" -lt 100 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($TMUX list-clients -F '#{client_key_mode}')" = 'Kitty 1' ] || exit 1
|
||||
|
||||
# kitty encodes the key, tmux parses it and encodes it again for the pane.
|
||||
try_key()
|
||||
{
|
||||
key=$1
|
||||
expected=$2
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t r: \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 20" || return 1
|
||||
sleep 1
|
||||
kitty @ --to "unix:$SOCKET" send-key "$key" 2>/dev/null || return 1
|
||||
i=0
|
||||
while [ ! -s "$OUT" ] && [ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$(tr -d ' \n' <"$OUT")" = "$expected" ]
|
||||
}
|
||||
|
||||
try_key ctrl+a '1b5b39373b3575' || exit 1
|
||||
try_key alt+a '1b5b39373b3375' || exit 1
|
||||
try_key ctrl+shift+a '1b5b39373b3675' || exit 1
|
||||
|
||||
# Super cannot be represented by the standard extended keys at all, so this
|
||||
# only succeeds if the whole chain used the Kitty protocol.
|
||||
try_key super+a '1b5b39373b3975' || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test pane-side Kitty keyboard protocol state and key encoding. This uses
|
||||
# synthetic protocol sequences and does not require a particular terminal.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
CONF=$(mktemp)
|
||||
OUT=$(mktemp)
|
||||
TMUX="$TEST_TMUX -LtestK$$ -f$CONF"
|
||||
|
||||
trap 'rm -f "$CONF" "$OUT"; $TMUX kill-server 2>/dev/null' 0 1 15
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' >"$CONF"
|
||||
|
||||
wait_for_output()
|
||||
{
|
||||
i=0
|
||||
while [ ! -s "$OUT" ] && [ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ -s "$OUT" ]
|
||||
}
|
||||
|
||||
wait_for_mode()
|
||||
{
|
||||
wanted=$1
|
||||
i=0
|
||||
while [ "$($TMUX display-message -pt: '#{pane_key_mode}')" != "$wanted" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($TMUX display-message -pt: '#{pane_key_mode}')" = "$wanted" ]
|
||||
}
|
||||
|
||||
check_output()
|
||||
{
|
||||
expected=$1
|
||||
actual=$(tr -d ' \n' <"$OUT")
|
||||
if [ "$actual" != "$expected" ]; then
|
||||
echo "expected $expected, got $actual"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
$TMUX new-session -d -x80 -y24 \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5" || exit 1
|
||||
wait_for_mode 'Kitty 1'
|
||||
$TMUX send-keys -t: C-S-a
|
||||
wait_for_output
|
||||
check_output 1b5b39373b3675
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_mode 'Kitty 1'
|
||||
$TMUX send-keys -t: s-a
|
||||
wait_for_output
|
||||
check_output 1b5b39373b3975
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>8u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_mode 'Kitty 8'
|
||||
$TMUX send-keys -t: a
|
||||
wait_for_output
|
||||
check_output 1b5b393775
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f3175
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>4;2m\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f3075
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u\033[>8u\033[<u\033[?u\033[>8u\033[<2u\033[?u'; dd bs=1 count=10 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f31751b5b3f3075
|
||||
|
||||
: >"$OUT"
|
||||
# "always" forces modifyOtherKeys mode 1, not Kitty keys.
|
||||
$TMUX set-option -g extended-keys always
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>0u\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f3075
|
||||
wait_for_mode 'Ext 1'
|
||||
$TMUX set-option -g extended-keys on
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u\033[?u\033[?1049h\033[?u\033[>8u\033[?u\033[?1049l\033[?u'; dd bs=1 count=20 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f31751b5b3f30751b5b3f38751b5b3f3175
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
@@ -400,6 +400,107 @@ $TMUX2 send-keys -t "$OUTER" a
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
$TMUX bind P display-popup -E -t "$p0" -w 20 -h 5 -T popup-title 'cat'
|
||||
$TMUX2 send-keys -t "$OUTER" C-b P
|
||||
sleep 1
|
||||
modal=$(fmt modal:0 '#{window_modal_pane}')
|
||||
[ -n "$modal" ] || fail "display-popup did not create a modal pane"
|
||||
must_equal "$(fmt "$modal" '#{pane_title}')" popup-title
|
||||
must_equal "$($TMUX show-options -pv -t "$modal" pane-border-status)" top
|
||||
must_equal "$($TMUX show-options -pv -t "$modal" pane-border-format)" \
|
||||
'#{pane_title}'
|
||||
$TMUX2 send-keys -t "$OUTER" C-b x z Enter
|
||||
sleep 1
|
||||
must_equal "$($TMUX show -gv @modal-prefix)" no
|
||||
must_equal "$($TMUX show -gv @modal-root)" no
|
||||
case "$($TMUX capture-pane -pt "$modal")" in
|
||||
*xz*) ;;
|
||||
*) fail "keys did not reach display-popup pane" ;;
|
||||
esac
|
||||
$TMUX2 send-keys -t "$OUTER" Escape
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" "$modal"
|
||||
$TMUX2 send-keys -t "$OUTER" C-c
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
# Creating a popup pane must not fire the split-window hook.
|
||||
check_ok set-hook -t modal after-split-window \
|
||||
"set-option -g @popup-after-split yes"
|
||||
check_ok set-option -g @popup-after-split no
|
||||
check_ok display-popup -E -t "$p0" true
|
||||
must_equal "$($TMUX show-option -gv @popup-after-split)" no
|
||||
check_ok set-hook -u -t modal after-split-window
|
||||
|
||||
# A borderless popup must not create a zero-sized pane in a tiny window.
|
||||
check_ok new-window -d -t modal: -n popup-small 'cat'
|
||||
check_ok set-option -w -t modal:popup-small window-size manual
|
||||
check_ok resize-window -t modal:popup-small -x 1 -y 1
|
||||
small=$(fmt modal:popup-small '#{pane_id}')
|
||||
check_ok bind Z display-popup -B -t "$small" 'cat'
|
||||
$TMUX2 send-keys -t "$OUTER" C-b Z
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:popup-small '#{window_panes}')" 1
|
||||
must_equal "$(fmt modal:popup-small '#{window_modal_pane}')" ''
|
||||
|
||||
$TMUX bind D display-popup -t "$p0" -w 20 -h 5 'printf done'
|
||||
$TMUX2 send-keys -t "$OUTER" C-b D
|
||||
sleep 2
|
||||
modal=$(fmt modal:0 '#{window_modal_pane}')
|
||||
[ -n "$modal" ] || fail "retained display-popup was not created"
|
||||
must_equal "$(fmt "$modal" '#{pane_dead}')" 1
|
||||
case "$($TMUX capture-pane -pt "$modal")" in
|
||||
*'Pane is dead'*) fail "display-popup showed remain-on-exit message" ;;
|
||||
esac
|
||||
$TMUX2 send-keys -t "$OUTER" a
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" "$modal"
|
||||
$TMUX2 send-keys -t "$OUTER" Escape
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
$TMUX bind K display-popup -k -t "$p0" -w 20 -h 5 'printf done'
|
||||
$TMUX2 send-keys -t "$OUTER" C-b K
|
||||
sleep 2
|
||||
modal=$(fmt modal:0 '#{window_modal_pane}')
|
||||
[ -n "$modal" ] || fail "display-popup -k was not created"
|
||||
must_equal "$(fmt "$modal" '#{pane_dead}')" 1
|
||||
$TMUX2 send-keys -t "$OUTER" a
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
$TMUX bind F display-popup -EE -t "$p0" -w 20 -h 5 'exit 1'
|
||||
$TMUX2 send-keys -t "$OUTER" C-b F
|
||||
sleep 2
|
||||
modal=$(fmt modal:0 '#{window_modal_pane}')
|
||||
[ -n "$modal" ] || fail "failed display-popup -EE did not remain"
|
||||
must_equal "$(fmt "$modal" '#{pane_dead}')" 1
|
||||
$TMUX2 send-keys -t "$OUTER" a
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" "$modal"
|
||||
$TMUX2 send-keys -t "$OUTER" Escape
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" "$modal"
|
||||
check_ok kill-pane -t "$modal"
|
||||
sleep 1
|
||||
|
||||
check_ok display-popup -EE -t "$p0" true
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
$TMUX bind G display-popup -EE -k -t "$p0" -w 20 -h 5 'exit 1'
|
||||
$TMUX2 send-keys -t "$OUTER" C-b G
|
||||
sleep 2
|
||||
modal=$(fmt modal:0 '#{window_modal_pane}')
|
||||
[ -n "$modal" ] || fail "failed display-popup -EE -k did not remain"
|
||||
must_equal "$(fmt "$modal" '#{pane_dead}')" 1
|
||||
must_equal "$($TMUX show-options -pv -t "$modal" remain-on-exit)" failed-key
|
||||
$TMUX2 send-keys -t "$OUTER" a
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
check_ok display-popup -EE -k -t "$p0" true
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
# A nonmodal floating pane may remain above zoom, and switching between it and
|
||||
# the zoomed tiled pane must not unzoom the window.
|
||||
check_ok new-window -d -t modal: -n float-over-zoom 'cat'
|
||||
|
||||
@@ -86,11 +86,6 @@ check_value "-gv status-keys" "vi"
|
||||
check_fail "unknown value: bogus" set -g status-keys bogus
|
||||
check_value "-gv status-keys" "vi"
|
||||
|
||||
# pane-border-lines accepts rounded as a pane border style.
|
||||
check_ok set -gw pane-border-lines rounded
|
||||
check_value "-gwv pane-border-lines" "rounded"
|
||||
check_ok set -gw pane-border-lines single
|
||||
|
||||
# --- flag options ---------------------------------------------------------
|
||||
#
|
||||
# focus-events is an on/off flag. Setting with no value toggles it; explicit
|
||||
|
||||
@@ -107,12 +107,6 @@ $TMUX2 new-pane -x28 -y8 -X4 -Y1 -B double \
|
||||
"sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||
compare floating-border-double
|
||||
|
||||
# Larger floating pane with rounded border lines.
|
||||
new_scene 40 12
|
||||
$TMUX2 new-pane -x28 -y8 -X4 -Y1 -B rounded \
|
||||
"sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||
compare floating-border-rounded
|
||||
|
||||
# Floating pane with no border lines: redraw_mark_pane_borders returns early so
|
||||
# the float has no border at all, only its (clipped) content over the base pane.
|
||||
new_scene 40 12
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Exercise drawing of popups (display-popup) over the window scene. A popup is an
|
||||
# overlay drawn on top of the redraw scene (the overlay_draw path in
|
||||
# screen-redraw.c), so this guards against regressions in how popups appear.
|
||||
#
|
||||
# A popup is modal and stays open until its command exits, so each scene fully
|
||||
# re-creates the servers and re-attaches; the popup is opened in the background
|
||||
# (display-popup blocks the client that runs it) and the outer pane is captured
|
||||
# while it is open.
|
||||
#
|
||||
# Run with GENERATE=1 to (re)create the golden files.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX=
|
||||
TMUX2=
|
||||
SETUP=0
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
cleanup() {
|
||||
rm -f "$TMP"
|
||||
[ -n "$TMUX" ] && $TMUX kill-server 2>/dev/null
|
||||
[ -n "$TMUX2" ] && $TMUX2 kill-server 2>/dev/null
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
fail() {
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
compare() {
|
||||
sleep 1
|
||||
$TMUX capturep -p >$TMP || exit 1
|
||||
if [ -n "$GENERATE" ]; then
|
||||
cp $TMP "$RESULTS/$1.result" || exit 1
|
||||
echo "generated $1"
|
||||
else
|
||||
cmp -s $TMP "$RESULTS/$1.result" || \
|
||||
fail "scene $1 differs from $RESULTS/$1.result"
|
||||
fi
|
||||
}
|
||||
|
||||
C="sh -c 'i=0; while [ \$i -lt 13 ]; do printf \"POP%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'"
|
||||
|
||||
# setup: fresh inner window attached inside a fresh outer pane, 40x14.
|
||||
setup() {
|
||||
[ -n "$TMUX" ] && $TMUX kill-server 2>/dev/null
|
||||
[ -n "$TMUX2" ] && $TMUX2 kill-server 2>/dev/null
|
||||
SETUP=$((SETUP + 1))
|
||||
TMUX="$TEST_TMUX -LtestA$$-$SETUP -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$-$SETUP -f/dev/null"
|
||||
$TMUX2 new -d -x40 -y14 "$C" || exit 1
|
||||
$TMUX2 set -g status off || exit 1
|
||||
$TMUX2 set -g window-size manual || exit 1
|
||||
$TMUX2 resizew -x40 -y14 || exit 1
|
||||
$TMUX new -d -x40 -y14 || exit 1
|
||||
$TMUX set -g status off || exit 1
|
||||
$TMUX set -g window-size manual || exit 1
|
||||
$TMUX set -g default-terminal "tmux-256color" || exit 1
|
||||
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||
$TMUX send Enter || exit 1
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# popup <args>: open a popup running a fixed command, in the background (it stays
|
||||
# open because the command sleeps; the servers are killed at the next setup).
|
||||
popup() {
|
||||
$TMUX2 display-popup "$@" -E "sh -c 'printf POPUP; exec sleep 100'" &
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# Basic popup over a single pane.
|
||||
setup
|
||||
popup -w20 -h6 -x6 -y3
|
||||
compare popup-basic
|
||||
|
||||
# Popup over a split: drawn on top of the pane border.
|
||||
setup
|
||||
$TMUX2 splitw -h "$C" || exit 1
|
||||
popup -w24 -h8 -x8 -y3
|
||||
compare popup-over-split
|
||||
|
||||
# Popup with no border lines (-B).
|
||||
setup
|
||||
popup -B -w20 -h6 -x6 -y3
|
||||
compare popup-noborder
|
||||
|
||||
# Popup with double border lines.
|
||||
setup
|
||||
popup -b double -w20 -h6 -x6 -y3
|
||||
compare popup-double
|
||||
|
||||
exit 0
|
||||
@@ -1,12 +0,0 @@
|
||||
base
|
||||
╭──────────────────────────╮
|
||||
│FLOAT │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────╯
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
POP00 ┌──────────────────┐
|
||||
POP01 │POPUP │
|
||||
POP02 │ │
|
||||
POP03 │ │
|
||||
POP04 │ │
|
||||
POP05 └──────────────────┘
|
||||
POP06 abcdefghij
|
||||
POP07 abcdefghij
|
||||
POP08 abcdefghij
|
||||
POP09 abcdefghij
|
||||
POP10 abcdefghij
|
||||
POP11 abcdefghij
|
||||
POP12 abcdefghij
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
POP00 ╔══════════════════╗
|
||||
POP01 ║POPUP ║
|
||||
POP02 ║ ║
|
||||
POP03 ║ ║
|
||||
POP04 ║ ║
|
||||
POP05 ╚══════════════════╝
|
||||
POP06 abcdefghij
|
||||
POP07 abcdefghij
|
||||
POP08 abcdefghij
|
||||
POP09 abcdefghij
|
||||
POP10 abcdefghij
|
||||
POP11 abcdefghij
|
||||
POP12 abcdefghij
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
POP00 POPUP
|
||||
POP01
|
||||
POP02
|
||||
POP03
|
||||
POP04
|
||||
POP05
|
||||
POP06 abcdefghij
|
||||
POP07 abcdefghij
|
||||
POP08 abcdefghij
|
||||
POP09 abcdefghij
|
||||
POP10 abcdefghij
|
||||
POP11 abcdefghij
|
||||
POP12 abcdefghij
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
POP00 ab┌──────────────────────┐fghij
|
||||
POP01 ab│POPUP │fghij
|
||||
POP02 ab│ │fghij
|
||||
POP03 ab│ │fghij
|
||||
POP04 ab│ │fghij
|
||||
POP05 ab│ │fghij
|
||||
POP06 ab│ │fghij
|
||||
POP07 ab└──────────────────────┘fghij
|
||||
POP08 abcdefghij │POP08 abcdefghij
|
||||
POP09 abcdefghij │POP09 abcdefghij
|
||||
POP10 abcdefghij │POP10 abcdefghij
|
||||
POP11 abcdefghij │POP11 abcdefghij
|
||||
POP12 abcdefghij │POP12 abcdefghij
|
||||
│
|
||||
@@ -33,7 +33,7 @@
|
||||
* this is done at various points, such as when a pane is moved or resized. The
|
||||
* scene only includes the part of the client used for the window: panes, pane
|
||||
* status lines, borders, scrollbars, and any area outside the window. The
|
||||
* client status line and overlay are not included.
|
||||
* client status line is not included.
|
||||
*
|
||||
* A scene is made from spans. A span is a horizontal run of cells on one
|
||||
* visible line that can be drawn in the same way. Each span has a type, for
|
||||
@@ -93,7 +93,6 @@ enum redraw_span_type {
|
||||
#define REDRAW_PANE_SCROLLBAR 0x20
|
||||
#define REDRAW_STATUS 0x40
|
||||
#define REDRAW_MENU 0x80
|
||||
#define REDRAW_OVERLAY 0x100
|
||||
|
||||
/* Draw everything. */
|
||||
#define REDRAW_ALL 0x7fffffff
|
||||
@@ -264,8 +263,6 @@ redraw_flags_to_string(int flags)
|
||||
strlcat(s, "scrollbar ", sizeof s);
|
||||
if (flags & REDRAW_MENU)
|
||||
strlcat(s, "menu ", sizeof s);
|
||||
if (flags & REDRAW_OVERLAY)
|
||||
strlcat(s, "overlay ", sizeof s);
|
||||
if (REDRAW_IS_ALL(flags))
|
||||
strlcat(s, "all ", sizeof s);
|
||||
if (*s != '\0')
|
||||
@@ -1381,45 +1378,30 @@ static void
|
||||
redraw_draw_span(struct redraw_draw_ctx *dctx, struct redraw_span *span,
|
||||
u_int y)
|
||||
{
|
||||
struct redraw_scene *scene = dctx->scene;
|
||||
struct redraw_span_data *data = &span->data;
|
||||
enum redraw_span_type type = data->type;
|
||||
struct client *c = scene->c;
|
||||
struct tty *tty = &c->tty;
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *rr;
|
||||
u_int i, x, n;
|
||||
|
||||
if (type == REDRAW_SPAN_STATUS && ~data->st.wp->flags & PANE_NEWSTATUS)
|
||||
return;
|
||||
|
||||
r = tty_check_overlay_range(tty, span->x, y, span->width);
|
||||
for (i = 0; i < r->used; i++) {
|
||||
rr = &r->ranges[i];
|
||||
if (rr->nx == 0)
|
||||
continue;
|
||||
x = rr->px;
|
||||
n = rr->nx;
|
||||
|
||||
switch (span->data.type) {
|
||||
case REDRAW_SPAN_PANE:
|
||||
redraw_draw_pane_span(dctx, span, x, y, n);
|
||||
break;
|
||||
case REDRAW_SPAN_BORDER:
|
||||
case REDRAW_SPAN_EMPTY:
|
||||
case REDRAW_SPAN_OUTSIDE:
|
||||
redraw_draw_border_span(dctx, span, x, y, n);
|
||||
break;
|
||||
case REDRAW_SPAN_STATUS:
|
||||
redraw_draw_status_span(dctx, span, x, y, n);
|
||||
break;
|
||||
case REDRAW_SPAN_SCROLLBAR:
|
||||
redraw_draw_scrollbar_span(dctx, span, x, y, n);
|
||||
break;
|
||||
case REDRAW_SPAN_MENU:
|
||||
redraw_draw_menu_span(dctx, span, x, y, n);
|
||||
break;
|
||||
}
|
||||
switch (span->data.type) {
|
||||
case REDRAW_SPAN_PANE:
|
||||
redraw_draw_pane_span(dctx, span, span->x, y, span->width);
|
||||
break;
|
||||
case REDRAW_SPAN_BORDER:
|
||||
case REDRAW_SPAN_EMPTY:
|
||||
case REDRAW_SPAN_OUTSIDE:
|
||||
redraw_draw_border_span(dctx, span, span->x, y, span->width);
|
||||
break;
|
||||
case REDRAW_SPAN_STATUS:
|
||||
redraw_draw_status_span(dctx, span, span->x, y, span->width);
|
||||
break;
|
||||
case REDRAW_SPAN_SCROLLBAR:
|
||||
redraw_draw_scrollbar_span(dctx, span, span->x, y, span->width);
|
||||
break;
|
||||
case REDRAW_SPAN_MENU:
|
||||
redraw_draw_menu_span(dctx, span, span->x, y, span->width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1688,10 +1670,8 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags)
|
||||
struct screen *sl;
|
||||
struct redraw_scene *scene;
|
||||
struct window_pane *loop;
|
||||
u_int width, i, y, lines, j;
|
||||
u_int width, i, y, lines;
|
||||
struct redraw_span *first;
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *rr;
|
||||
int redraw;
|
||||
|
||||
if (c->flags & CLIENT_SUSPENDED)
|
||||
@@ -1799,19 +1779,9 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags)
|
||||
else
|
||||
y = c->tty.sy - lines;
|
||||
sl = c->status.active;
|
||||
for (i = 0; i < lines; i++) {
|
||||
r = tty_check_overlay_range(tty, 0, y + i, tty->sx);
|
||||
for (j = 0; j < r->used; j++) {
|
||||
rr = &r->ranges[j];
|
||||
if (rr->nx == 0)
|
||||
continue;
|
||||
tty_draw_line(tty, sl, rr->px, i, rr->nx,
|
||||
rr->px, y + i, NULL);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < lines; i++)
|
||||
tty_draw_line(tty, sl, 0, i, tty->sx, 0, y + i, NULL);
|
||||
}
|
||||
if (c->overlay_draw != NULL && (flags & REDRAW_OVERLAY))
|
||||
c->overlay_draw(c, c->overlay_data);
|
||||
|
||||
tty_reset(tty);
|
||||
|
||||
@@ -1867,18 +1837,13 @@ redraw_screen(struct client *c)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (c->flags & CLIENT_REDRAWWINDOW) {
|
||||
if (c->flags & CLIENT_REDRAWOVERLAY)
|
||||
redraw_draw(c, NULL, REDRAW_ALL);
|
||||
else
|
||||
redraw_draw(c, NULL, REDRAW_ALL & ~REDRAW_OVERLAY);
|
||||
} else {
|
||||
if (c->flags & CLIENT_REDRAWWINDOW)
|
||||
redraw_draw(c, NULL, REDRAW_ALL);
|
||||
else {
|
||||
if (c->flags & CLIENT_REDRAWBORDERS)
|
||||
flags |= (REDRAW_PANE_BORDER|REDRAW_PANE_STATUS);
|
||||
if (c->flags & CLIENT_REDRAWSTATUS)
|
||||
flags |= (REDRAW_STATUS|REDRAW_PANE_STATUS);
|
||||
if (c->flags & CLIENT_REDRAWOVERLAY)
|
||||
flags |= REDRAW_OVERLAY;
|
||||
if (c->flags & CLIENT_REDRAWMENU)
|
||||
flags |= REDRAW_MENU;
|
||||
if (c->session->curw->window->menu != NULL)
|
||||
|
||||
@@ -305,21 +305,16 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
|
||||
|
||||
if (~ctx->flags & SCREEN_WRITE_SYNC) {
|
||||
/*
|
||||
* For the active pane showing its base screen or for an
|
||||
* overlay (no pane), only use synchronized updates if
|
||||
* requested (commands that move the cursor); for other panes
|
||||
* or a pane in a mode, always use it, since the cursor will
|
||||
* have to move.
|
||||
* For the active pane showing its base screen, only use
|
||||
* synchronized updates if requested (commands that move the
|
||||
* cursor); for other panes or a pane in a mode, always use it,
|
||||
* since the cursor will have to move.
|
||||
*/
|
||||
if (ctx->wp != NULL && (ctx->wp != ctx->wp->window->active ||
|
||||
ctx->wp->screen != &ctx->wp->base))
|
||||
ttyctx->flags |= TTY_CTX_SYNC;
|
||||
else {
|
||||
if (ctx->wp == NULL)
|
||||
ttyctx->flags |= TTY_CTX_OVERLAY_SYNC;
|
||||
if (is_sync)
|
||||
ttyctx->flags |= TTY_CTX_SYNC;
|
||||
}
|
||||
else if (is_sync)
|
||||
ttyctx->flags |= TTY_CTX_SYNC;
|
||||
tty_write(tty_cmd_syncstart, ttyctx);
|
||||
ctx->flags |= SCREEN_WRITE_SYNC;
|
||||
}
|
||||
@@ -439,7 +434,6 @@ screen_write_reset(struct screen_write_ctx *ctx)
|
||||
|
||||
if (options_get_number(global_options, "extended-keys") == 2)
|
||||
s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
|
||||
input_kitty_reset(s);
|
||||
|
||||
screen_write_clearscreen(ctx, 8);
|
||||
screen_write_set_cursor(ctx, 0, 0);
|
||||
@@ -715,7 +709,7 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
|
||||
if (!window_position_is_visible(r, xoff + s->cx))
|
||||
break;
|
||||
ttyctx.cell = &gc;
|
||||
ttyctx.flags &= (TTY_CTX_OVERLAY_SYNC|TTY_CTX_SYNC);
|
||||
ttyctx.flags &= TTY_CTX_SYNC;
|
||||
tty_write(tty_cmd_cell, &ttyctx);
|
||||
ttyctx.ocx++;
|
||||
|
||||
|
||||
6
screen.c
6
screen.c
@@ -88,8 +88,6 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
|
||||
s->default_cstyle = SCREEN_CURSOR_DEFAULT;
|
||||
s->mode = MODE_CURSOR;
|
||||
s->default_mode = 0;
|
||||
memset(&s->kitty_keys, 0, sizeof s->kitty_keys);
|
||||
memset(&s->saved_kitty_keys, 0, sizeof s->saved_kitty_keys);
|
||||
s->ccolour = -1;
|
||||
s->default_ccolour = -1;
|
||||
s->tabs = NULL;
|
||||
@@ -120,9 +118,9 @@ screen_reinit(struct screen *s, int check)
|
||||
|
||||
if (options_get_number(global_options, "extended-keys") == 2)
|
||||
s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
|
||||
|
||||
if (SCREEN_IS_ALTERNATE(s))
|
||||
screen_alternate_off(s, NULL, 0);
|
||||
input_kitty_reset(s);
|
||||
s->saved_cx = UINT_MAX;
|
||||
s->saved_cy = UINT_MAX;
|
||||
|
||||
@@ -700,7 +698,6 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
|
||||
if (SCREEN_IS_ALTERNATE(s))
|
||||
return 0;
|
||||
input_kitty_alternate_on(s);
|
||||
sx = screen_size_x(s);
|
||||
sy = screen_size_y(s);
|
||||
|
||||
@@ -761,7 +758,6 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
s->cy = screen_size_y(s) - 1;
|
||||
return 0;
|
||||
}
|
||||
input_kitty_alternate_off(s);
|
||||
|
||||
/* Restore the saved grid. */
|
||||
grid_duplicate_lines(s->grid, screen_hsize(s), s->saved_grid, 0,
|
||||
|
||||
167
server-client.c
167
server-client.c
@@ -67,77 +67,6 @@ server_client_how_many(void)
|
||||
return (n);
|
||||
}
|
||||
|
||||
/* Overlay timer callback. */
|
||||
static void
|
||||
server_client_overlay_timer(__unused int fd, __unused short events, void *data)
|
||||
{
|
||||
server_client_clear_overlay(data);
|
||||
}
|
||||
|
||||
/* Set an overlay on client. */
|
||||
void
|
||||
server_client_set_overlay(struct client *c, u_int delay,
|
||||
overlay_check_cb checkcb, overlay_mode_cb modecb,
|
||||
overlay_draw_cb drawcb, overlay_key_cb keycb, overlay_free_cb freecb,
|
||||
overlay_resize_cb resizecb, void *data)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if (c->overlay_draw != NULL)
|
||||
server_client_clear_overlay(c);
|
||||
|
||||
tv.tv_sec = delay / 1000;
|
||||
tv.tv_usec = (delay % 1000) * 1000L;
|
||||
|
||||
if (event_initialized(&c->overlay_timer))
|
||||
evtimer_del(&c->overlay_timer);
|
||||
evtimer_set(&c->overlay_timer, server_client_overlay_timer, c);
|
||||
if (delay != 0)
|
||||
evtimer_add(&c->overlay_timer, &tv);
|
||||
|
||||
c->overlay_check = checkcb;
|
||||
c->overlay_mode = modecb;
|
||||
c->overlay_draw = drawcb;
|
||||
c->overlay_key = keycb;
|
||||
c->overlay_free = freecb;
|
||||
c->overlay_resize = resizecb;
|
||||
c->overlay_data = data;
|
||||
|
||||
if (c->overlay_check == NULL)
|
||||
c->tty.flags |= TTY_FREEZE;
|
||||
if (c->overlay_mode == NULL)
|
||||
c->tty.flags |= TTY_NOCURSOR;
|
||||
window_update_focus(c->session->curw->window);
|
||||
server_redraw_client(c);
|
||||
}
|
||||
|
||||
/* Clear overlay mode on client. */
|
||||
void
|
||||
server_client_clear_overlay(struct client *c)
|
||||
{
|
||||
if (c->overlay_draw == NULL)
|
||||
return;
|
||||
|
||||
if (event_initialized(&c->overlay_timer))
|
||||
evtimer_del(&c->overlay_timer);
|
||||
|
||||
if (c->overlay_free != NULL)
|
||||
c->overlay_free(c, c->overlay_data);
|
||||
|
||||
c->overlay_check = NULL;
|
||||
c->overlay_mode = NULL;
|
||||
c->overlay_draw = NULL;
|
||||
c->overlay_key = NULL;
|
||||
c->overlay_free = NULL;
|
||||
c->overlay_resize = NULL;
|
||||
c->overlay_data = NULL;
|
||||
|
||||
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
|
||||
if (c->session != NULL)
|
||||
window_update_focus(c->session->curw->window);
|
||||
server_redraw_client(c);
|
||||
}
|
||||
|
||||
/* Are these ranges empty? That is, nothing is visible. */
|
||||
int
|
||||
server_client_ranges_is_empty(struct visible_ranges *r)
|
||||
@@ -161,52 +90,6 @@ server_client_ensure_ranges(struct visible_ranges *r, u_int n)
|
||||
r->size = n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given overlay position and dimensions, return parts of the input range which
|
||||
* are visible.
|
||||
*/
|
||||
void
|
||||
server_client_overlay_range(u_int x, u_int y, u_int sx, u_int sy, u_int px,
|
||||
u_int py, u_int nx, struct visible_ranges *r)
|
||||
{
|
||||
u_int ox, onx;
|
||||
|
||||
/* Trivial case of no overlap in the y direction. */
|
||||
if (py < y || py > y + sy - 1) {
|
||||
server_client_ensure_ranges(r, 1);
|
||||
r->ranges[0].px = px;
|
||||
r->ranges[0].nx = nx;
|
||||
r->used = 1;
|
||||
return;
|
||||
}
|
||||
server_client_ensure_ranges(r, 2);
|
||||
|
||||
/* Visible bit to the left of the popup. */
|
||||
if (px < x) {
|
||||
r->ranges[0].px = px;
|
||||
r->ranges[0].nx = x - px;
|
||||
if (r->ranges[0].nx > nx)
|
||||
r->ranges[0].nx = nx;
|
||||
} else {
|
||||
r->ranges[0].px = 0;
|
||||
r->ranges[0].nx = 0;
|
||||
}
|
||||
|
||||
/* Visible bit to the right of the popup. */
|
||||
ox = x + sx;
|
||||
if (px > ox)
|
||||
ox = px;
|
||||
onx = px + nx;
|
||||
if (onx > ox) {
|
||||
r->ranges[1].px = ox;
|
||||
r->ranges[1].nx = onx - ox;
|
||||
} else {
|
||||
r->ranges[1].px = 0;
|
||||
r->ranges[1].nx = 0;
|
||||
}
|
||||
r->used = 2;
|
||||
}
|
||||
|
||||
/* Check if this client is inside this server. */
|
||||
int
|
||||
server_client_check_nested(struct client *c)
|
||||
@@ -490,7 +373,6 @@ server_client_lost(struct client *c)
|
||||
cfg_client = NULL;
|
||||
c->flags |= CLIENT_DEAD;
|
||||
|
||||
server_client_clear_overlay(c);
|
||||
status_prompt_clear(c);
|
||||
status_message_clear(c);
|
||||
|
||||
@@ -1746,10 +1628,6 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Handle theme reporting keys before overlays so they work even when a
|
||||
* popup is open.
|
||||
*/
|
||||
if (event->key == KEYC_REPORT_LIGHT_THEME) {
|
||||
server_client_report_theme(c, THEME_LIGHT);
|
||||
return (0);
|
||||
@@ -1760,10 +1638,9 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
}
|
||||
|
||||
/*
|
||||
* Key presses in overlay mode, dead panes waiting for a key, modal cancel
|
||||
* keys, panes capturing all keys and the command prompt are special cases.
|
||||
* The queue might be blocked so they need to be processed immediately
|
||||
* rather than queued.
|
||||
* Dead panes waiting for a key, modal cancel keys, panes capturing all keys
|
||||
* and the command prompt are special cases. The queue might be blocked so
|
||||
* they need to be processed immediately rather than queued.
|
||||
*/
|
||||
if (~c->flags & CLIENT_READONLY) {
|
||||
if (c->message_string != NULL) {
|
||||
@@ -1772,22 +1649,11 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
status_message_clear(c);
|
||||
}
|
||||
|
||||
if (c->overlay_key != NULL) {
|
||||
switch (c->overlay_key(c, c->overlay_data, event)) {
|
||||
case 0:
|
||||
return (0);
|
||||
case 1:
|
||||
server_client_clear_overlay(c);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
server_client_clear_overlay(c);
|
||||
|
||||
wp = s->curw->window->active;
|
||||
if (server_client_handle_dead_key(wp, event->key))
|
||||
return (0);
|
||||
if (wp != NULL && wp == wp->window->modal &&
|
||||
if (wp != NULL &&
|
||||
wp == wp->window->modal &&
|
||||
(wp->flags & PANE_CLOSEONCANCEL) &&
|
||||
(event->key == '\033' || event->key == ('c'|KEYC_CTRL))) {
|
||||
server_kill_pane(wp);
|
||||
@@ -2177,11 +2043,8 @@ server_client_reset_state(struct client *c)
|
||||
flags = (tty->flags & TTY_BLOCK);
|
||||
tty->flags &= ~TTY_BLOCK;
|
||||
|
||||
/* Get mode from overlay if any, else from screen. */
|
||||
if (c->overlay_draw != NULL) {
|
||||
if (c->overlay_mode != NULL)
|
||||
s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
|
||||
} else if (w->menu != NULL) {
|
||||
/* Get mode from the menu if any, else from the screen. */
|
||||
if (w->menu != NULL) {
|
||||
menu_get_cursor(w->menu, &cx, &cy);
|
||||
s = menu_screen(w->menu);
|
||||
} else if (wp != NULL && c->prompt == NULL)
|
||||
@@ -2194,7 +2057,6 @@ server_client_reset_state(struct client *c)
|
||||
log_debug("%s: client %s mode %s", __func__, c->name,
|
||||
screen_mode_to_string(mode));
|
||||
}
|
||||
tty_update_kitty(tty, s);
|
||||
|
||||
/* Reset region and margin. */
|
||||
tty_region_off(tty);
|
||||
@@ -2204,7 +2066,7 @@ server_client_reset_state(struct client *c)
|
||||
if (c->prompt != NULL) {
|
||||
prompt = 1;
|
||||
status_prompt_cursor(c, &cx, &cy);
|
||||
} else if (wp != NULL && c->overlay_draw == NULL) {
|
||||
} else if (wp != NULL) {
|
||||
if (w->menu != NULL) {
|
||||
tty_window_offset(tty, &ox, &oy, &sx, &sy);
|
||||
if (cx < ox || cx >= ox + sx ||
|
||||
@@ -2259,7 +2121,7 @@ server_client_reset_state(struct client *c)
|
||||
if (!cursor)
|
||||
mode &= ~MODE_CURSOR;
|
||||
}
|
||||
} else if (c->overlay_mode == NULL || s == NULL)
|
||||
} else if (s == NULL)
|
||||
mode &= ~MODE_CURSOR;
|
||||
if (~pane_mode & MODE_SYNC) {
|
||||
log_debug("%s: cursor to %u,%u", __func__, cx, cy);
|
||||
@@ -2276,7 +2138,7 @@ server_client_reset_state(struct client *c)
|
||||
* movement events.
|
||||
*/
|
||||
if (options_get_number(oo, "mouse")) {
|
||||
if (c->overlay_draw == NULL && w->menu == NULL) {
|
||||
if (w->menu == NULL) {
|
||||
mode &= ~ALL_MOUSE_MODES;
|
||||
TAILQ_FOREACH(loop, &w->panes, entry) {
|
||||
if (loop->screen->mode & MODE_MOUSE_ALL)
|
||||
@@ -2292,7 +2154,7 @@ server_client_reset_state(struct client *c)
|
||||
}
|
||||
|
||||
/* Clear bracketed paste mode if at the prompt. */
|
||||
if (c->overlay_draw == NULL && prompt)
|
||||
if (prompt)
|
||||
mode &= ~MODE_BRACKETPASTE;
|
||||
|
||||
/* Set the terminal mode and reset attributes. */
|
||||
@@ -2494,11 +2356,10 @@ server_client_check_redraw(struct client *c)
|
||||
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
|
||||
return;
|
||||
if (c->flags & CLIENT_ALLREDRAWFLAGS) {
|
||||
log_debug("%s: redraw%s%s%s%s%s", c->name,
|
||||
log_debug("%s: redraw%s%s%s%s", c->name,
|
||||
(c->flags & CLIENT_REDRAWWINDOW) ? " window" : "",
|
||||
(c->flags & CLIENT_REDRAWSTATUS) ? " status" : "",
|
||||
(c->flags & CLIENT_REDRAWBORDERS) ? " borders" : "",
|
||||
(c->flags & CLIENT_REDRAWOVERLAY) ? " overlay" : "",
|
||||
(c->flags & CLIENT_REDRAWMENU) ? " menu" : "");
|
||||
}
|
||||
|
||||
@@ -2706,10 +2567,6 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
tty_resize(&c->tty);
|
||||
tty_repeat_requests(&c->tty, 0);
|
||||
recalculate_sizes();
|
||||
if (c->overlay_resize == NULL)
|
||||
server_client_clear_overlay(c);
|
||||
else
|
||||
c->overlay_resize(c, c->overlay_data);
|
||||
server_redraw_client(c);
|
||||
if (c->session != NULL)
|
||||
server_client_fire_resized(c, old_sx, old_sy);
|
||||
|
||||
2
status.c
2
status.c
@@ -577,8 +577,6 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
|
||||
struct prompt_create_data pd;
|
||||
struct status_prompt_data *spd;
|
||||
|
||||
server_client_clear_overlay(c);
|
||||
|
||||
status_message_clear(c);
|
||||
status_prompt_clear(c);
|
||||
status_push_screen(c);
|
||||
|
||||
255
tmux.1
255
tmux.1
@@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: tmux.1,v 1.1170 2026/09/11 10:17:16 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.1169 2026/09/10 11:02:18 nicm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
.\"
|
||||
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 11 2026 $
|
||||
.Dd $Mdocdate: September 10 2026 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -4907,30 +4907,14 @@ If enabled, the server will exit when there are no attached clients.
|
||||
.It Xo Ic extended\-keys
|
||||
.Op Ic on | off | always
|
||||
.Xc
|
||||
Controls how modified keys are reported.
|
||||
When enabled,
|
||||
.Nm
|
||||
uses the Kitty keyboard protocol with terminals which support it, and the
|
||||
Controls how modified keys (keys pressed together with Control, Meta, or Shift)
|
||||
are reported.
|
||||
This is the equivalent of the
|
||||
.Ic modifyOtherKeys
|
||||
.Xr xterm 1
|
||||
resource with other terminals which support extended keys.
|
||||
Each client uses the best that its terminal supports, so clients with different
|
||||
terminals may be attached at the same time.
|
||||
resource.
|
||||
.Pp
|
||||
Programs inside panes may request either the Kitty keyboard protocol or
|
||||
.Ic modifyOtherKeys ,
|
||||
and keys are sent to each program in the form it requested, whichever client
|
||||
they were typed on.
|
||||
The Kitty keyboard protocol can report the Super and Hyper modifiers, whose key
|
||||
name prefixes are
|
||||
.Ql s-
|
||||
and
|
||||
.Ql H- ;
|
||||
its disambiguate and report-all enhancements are supported.
|
||||
.Pp
|
||||
For
|
||||
.Ic modifyOtherKeys ,
|
||||
when set to
|
||||
When set to
|
||||
.Ic on ,
|
||||
the program inside the pane can request one of two modes: mode 1 which changes
|
||||
the sequence for only keys which lack an existing well-known representation; or
|
||||
@@ -4939,35 +4923,26 @@ When set to
|
||||
.Ic always ,
|
||||
modes 1 and 2 can still be requested by applications, but mode 1 will be forced
|
||||
instead of the standard mode.
|
||||
This applies only to applications inside panes; it does not force the Kitty
|
||||
keyboard protocol or change what
|
||||
.Nm
|
||||
requests from the terminal.
|
||||
When set to
|
||||
.Ic off ,
|
||||
this feature is disabled and only standard keys are reported.
|
||||
.Pp
|
||||
.Nm
|
||||
will always request extended keys itself if the terminal supports them.
|
||||
Support for the Kitty keyboard protocol is detected when a client attaches.
|
||||
See also the
|
||||
.Ic kittykeys
|
||||
and
|
||||
.Ic extkeys
|
||||
features for the
|
||||
feature for the
|
||||
.Ic terminal\-features
|
||||
option, the
|
||||
.Ic extended\-keys\-format
|
||||
option and the
|
||||
.Ic pane_key_mode
|
||||
and
|
||||
.Ic client_key_mode
|
||||
variables.
|
||||
variable.
|
||||
.It Xo Ic extended\-keys\-format
|
||||
.Op Ic csi\-u | xterm | kitty
|
||||
.Op Ic csi\-u | xterm
|
||||
.Xc
|
||||
Selects the format for reporting modified keys to programs which request
|
||||
.Ic modifyOtherKeys .
|
||||
Selects one of the two possible formats for reporting modified keys to
|
||||
applications.
|
||||
This is the equivalent of the
|
||||
.Ic formatOtherKeys
|
||||
.Xr xterm 1
|
||||
@@ -4980,11 +4955,6 @@ and as
|
||||
.Ql \[ha][[65;6u
|
||||
when set to
|
||||
.Ic csi\-u .
|
||||
.Ic kitty
|
||||
is accepted for compatibility and is the same as
|
||||
.Ic csi\-u ;
|
||||
programs which request the Kitty keyboard protocol receive it whatever this
|
||||
option is set to.
|
||||
.It Xo Ic focus\-events
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -5133,9 +5103,6 @@ Ignore function keys from
|
||||
and use the
|
||||
.Nm
|
||||
internal set only.
|
||||
.It kittykeys
|
||||
Supports the Kitty keyboard protocol.
|
||||
This is added automatically if the terminal answers the Kitty keyboard query.
|
||||
.It margins
|
||||
Supports DECSLRM margins.
|
||||
.It mouse
|
||||
@@ -5386,10 +5353,16 @@ section on how to specify
|
||||
.Ar style .
|
||||
.It Ic menu\-border\-lines Ar type
|
||||
Set the type of characters used for drawing menu borders.
|
||||
See
|
||||
.Ic popup\-border\-lines
|
||||
for possible values for
|
||||
.Ar border\-lines .
|
||||
.Ar type
|
||||
may be one of
|
||||
.Ic single ,
|
||||
.Ic rounded ,
|
||||
.Ic double ,
|
||||
.Ic heavy ,
|
||||
.Ic simple ,
|
||||
.Ic padded ,
|
||||
or
|
||||
.Ic none .
|
||||
.It Ic message\-command\-style Ar style
|
||||
Set status line message command style.
|
||||
This is used for the command prompt with
|
||||
@@ -6013,8 +5986,6 @@ single lines using ACS or UTF\-8 characters
|
||||
double lines using UTF\-8 characters
|
||||
.It heavy
|
||||
heavy lines using UTF\-8 characters
|
||||
.It rounded
|
||||
single lines with rounded corners using UTF\-8 characters
|
||||
.It simple
|
||||
simple ASCII characters
|
||||
.It number
|
||||
@@ -6049,48 +6020,6 @@ see the
|
||||
section.
|
||||
Attributes are ignored.
|
||||
.Pp
|
||||
.It Ic popup\-style Ar style
|
||||
Set the popup style.
|
||||
See the
|
||||
.Sx STYLES
|
||||
section on how to specify
|
||||
.Ar style .
|
||||
Attributes are ignored.
|
||||
.Pp
|
||||
.It Ic popup\-border\-style Ar style
|
||||
Set the popup border style.
|
||||
See the
|
||||
.Sx STYLES
|
||||
section on how to specify
|
||||
.Ar style .
|
||||
Attributes are ignored.
|
||||
.Pp
|
||||
.It Ic popup\-border\-lines Ar type
|
||||
Set the type of characters used for drawing popup borders.
|
||||
.Ar type
|
||||
may be one of:
|
||||
.Bl -tag -width Ds
|
||||
.It single
|
||||
single lines using ACS or UTF\-8 characters (default)
|
||||
.It rounded
|
||||
variation of single with rounded corners using UTF\-8 characters
|
||||
.It double
|
||||
double lines using UTF\-8 characters
|
||||
.It heavy
|
||||
heavy lines using UTF\-8 characters
|
||||
.It simple
|
||||
simple ASCII characters
|
||||
.It padded
|
||||
simple ASCII space character
|
||||
.It none
|
||||
no border
|
||||
.El
|
||||
.Pp
|
||||
.Ql double
|
||||
and
|
||||
.Ql heavy
|
||||
will fall back to standard ACS line drawing when UTF\-8 is not supported.
|
||||
.Pp
|
||||
.It Xo Ic pane\-scrollbars
|
||||
.Op Ic off | modal | on | auto\-hide
|
||||
.Xc
|
||||
@@ -7342,7 +7271,6 @@ The following variables are available, where appropriate:
|
||||
.It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind"
|
||||
.It Li "client_flags" Ta "" Ta "List of client flags"
|
||||
.It Li "client_height" Ta "" Ta "Height of client"
|
||||
.It Li "client_key_mode" Ta "" Ta "Extended key reporting mode for this client"
|
||||
.It Li "client_key_table" Ta "" Ta "Current key table"
|
||||
.It Li "client_last_session" Ta "" Ta "Name of the client's last session"
|
||||
.It Li "client_name" Ta "" Ta "Name of client"
|
||||
@@ -8238,10 +8166,16 @@ command should be omitted.
|
||||
.Pp
|
||||
.Fl b
|
||||
sets the type of characters used for drawing menu borders.
|
||||
See
|
||||
.Ic popup\-border\-lines
|
||||
for possible values for
|
||||
.Ar border\-lines .
|
||||
.Ar border\-lines
|
||||
may be one of
|
||||
.Ic single ,
|
||||
.Ic rounded ,
|
||||
.Ic double ,
|
||||
.Ic heavy ,
|
||||
.Ic simple ,
|
||||
.Ic padded ,
|
||||
or
|
||||
.Ic none .
|
||||
.Pp
|
||||
.Fl H
|
||||
sets the style for the selected menu item (see
|
||||
@@ -8277,15 +8211,18 @@ Both may be a row or column number, or one of the following special values:
|
||||
.It Li "S" Ta Fl y Ta "The line above or below the status line"
|
||||
.El
|
||||
.Pp
|
||||
Or a format, which is expanded including the following additional variables:
|
||||
Or a format, which is expanded with the following additional variables.
|
||||
The
|
||||
.Ql popup_
|
||||
prefix is retained for compatibility:
|
||||
.Bl -column "XXXXXXXXXXXXXXXXXXXXXXXXXX" -offset indent
|
||||
.It Sy "Variable name" Ta Sy "Replaced with"
|
||||
.It Li "popup_centre_x" Ta "Centered in the client"
|
||||
.It Li "popup_centre_y" Ta "Centered in the client"
|
||||
.It Li "popup_height" Ta "Height of menu or popup"
|
||||
.It Li "popup_centre_x" Ta "Centered in the window"
|
||||
.It Li "popup_centre_y" Ta "Centered in the window"
|
||||
.It Li "popup_height" Ta "Height of the menu"
|
||||
.It Li "popup_last_x" Ta "Left of the last menu"
|
||||
.It Li "popup_last_y" Ta "Bottom of the last menu"
|
||||
.It Li "popup_mouse_bottom" Ta "Bottom of at the mouse"
|
||||
.It Li "popup_mouse_bottom" Ta "Bottom at the mouse"
|
||||
.It Li "popup_mouse_centre_x" Ta "Horizontal centre at the mouse"
|
||||
.It Li "popup_mouse_centre_y" Ta "Vertical centre at the mouse"
|
||||
.It Li "popup_mouse_top" Ta "Top at the mouse"
|
||||
@@ -8296,7 +8233,7 @@ Or a format, which is expanded including the following additional variables:
|
||||
.It Li "popup_pane_right" Ta "Right of the pane"
|
||||
.It Li "popup_pane_top" Ta "Top of the pane"
|
||||
.It Li "popup_status_line_y" Ta "Above or below the status line"
|
||||
.It Li "popup_width" Ta "Width of menu or popup"
|
||||
.It Li "popup_width" Ta "Width of the menu"
|
||||
.It Li "popup_window_status_line_x" Ta "At the window position in status line"
|
||||
.It Li "popup_window_status_line_y" Ta "At the status line showing the window"
|
||||
.El
|
||||
@@ -8382,116 +8319,6 @@ lists the format variables and their values.
|
||||
.Fl I
|
||||
forwards any input read from stdin to the empty pane given by
|
||||
.Ar target\-pane .
|
||||
.Tg popup
|
||||
.It Xo Ic display\-popup
|
||||
.Op Fl BCEkN
|
||||
.Op Fl b Ar border\-lines
|
||||
.Op Fl c Ar target\-client
|
||||
.Op Fl d Ar start\-directory
|
||||
.Op Fl e Ar environment
|
||||
.Op Fl h Ar height
|
||||
.Op Fl s Ar style
|
||||
.Op Fl S Ar border\-style
|
||||
.Op Fl t Ar target\-pane
|
||||
.Op Fl T Ar title
|
||||
.Op Fl w Ar width
|
||||
.Op Fl x Ar position
|
||||
.Op Fl y Ar position
|
||||
.Op Ar shell\-command Op Ar argument ...
|
||||
.Xc
|
||||
.D1 Pq alias: Ic popup
|
||||
Display a popup running
|
||||
.Ar shell\-command
|
||||
(or
|
||||
.Ar default\-command
|
||||
when omitted) on
|
||||
.Ar target\-client .
|
||||
A popup is a rectangular box drawn over the top of any panes.
|
||||
If the command is run inside an existing popup, that popup is modified.
|
||||
Only the
|
||||
.Fl b ,
|
||||
.Fl B ,
|
||||
.Fl C ,
|
||||
.Fl E ,
|
||||
.Fl EE ,
|
||||
.Fl K ,
|
||||
.Fl N ,
|
||||
.Fl s ,
|
||||
and
|
||||
.Fl S
|
||||
options are accepted in this case;
|
||||
all others are ignored.
|
||||
.Pp
|
||||
.Fl E
|
||||
closes the popup automatically when
|
||||
.Ar shell\-command
|
||||
exits.
|
||||
Two
|
||||
.Fl E
|
||||
closes the popup only if
|
||||
.Ar shell\-command
|
||||
exited with success.
|
||||
.Fl k
|
||||
allows any key to dismiss the popup instead of only
|
||||
.Ql Escape
|
||||
or
|
||||
.Ql C\-c .
|
||||
.Pp
|
||||
.Fl x
|
||||
and
|
||||
.Fl y
|
||||
give the position of the popup, they have the same meaning as for the
|
||||
.Ic display\-menu
|
||||
command.
|
||||
.Fl w
|
||||
and
|
||||
.Fl h
|
||||
give the width and height - both may be a percentage (followed by
|
||||
.Ql % ) .
|
||||
If omitted, half of the terminal size is used.
|
||||
.Pp
|
||||
.Fl B
|
||||
does not surround the popup by a border.
|
||||
.Pp
|
||||
.Fl b
|
||||
sets the type of characters used for drawing popup borders.
|
||||
When
|
||||
.Fl B
|
||||
is specified, the
|
||||
.Fl b
|
||||
option is ignored.
|
||||
See
|
||||
.Ic popup\-border\-lines
|
||||
for possible values for
|
||||
.Ar border\-lines .
|
||||
.Pp
|
||||
.Fl s
|
||||
sets the style for the popup and
|
||||
.Fl S
|
||||
sets the style for the popup border (see
|
||||
.Sx STYLES ) .
|
||||
.Pp
|
||||
.Fl e
|
||||
takes the form
|
||||
.Ql VARIABLE=value
|
||||
and sets an environment variable for the popup; it may be specified multiple
|
||||
times.
|
||||
.Pp
|
||||
.Fl T
|
||||
is a format for the popup title (see
|
||||
.Sx FORMATS ) .
|
||||
.Pp
|
||||
The
|
||||
.Fl C
|
||||
flag closes any popup on the client.
|
||||
.Pp
|
||||
.Fl N
|
||||
disables any previously specified
|
||||
.Fl E ,
|
||||
.Fl EE ,
|
||||
or
|
||||
.Fl k
|
||||
option.
|
||||
.Tg showphist
|
||||
.It Xo Ic show\-prompt\-history
|
||||
.Op Fl T Ar prompt\-type
|
||||
|
||||
164
tmux.h
164
tmux.h
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.h,v 1.1440 2026/09/11 10:17:16 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1439 2026/09/10 11:02:18 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -142,8 +142,6 @@ struct winlink;
|
||||
#define VISUAL_BOTH 2
|
||||
|
||||
/* Key modifier bits. */
|
||||
#define KEYC_SUPER 0x00010000000000ULL
|
||||
#define KEYC_HYPER 0x00020000000000ULL
|
||||
#define KEYC_META 0x00100000000000ULL
|
||||
#define KEYC_CTRL 0x00200000000000ULL
|
||||
#define KEYC_SHIFT 0x00400000000000ULL
|
||||
@@ -376,29 +374,6 @@ enum {
|
||||
KEYC_F10,
|
||||
KEYC_F11,
|
||||
KEYC_F12,
|
||||
KEYC_F13,
|
||||
KEYC_F14,
|
||||
KEYC_F15,
|
||||
KEYC_F16,
|
||||
KEYC_F17,
|
||||
KEYC_F18,
|
||||
KEYC_F19,
|
||||
KEYC_F20,
|
||||
KEYC_F21,
|
||||
KEYC_F22,
|
||||
KEYC_F23,
|
||||
KEYC_F24,
|
||||
KEYC_F25,
|
||||
KEYC_F26,
|
||||
KEYC_F27,
|
||||
KEYC_F28,
|
||||
KEYC_F29,
|
||||
KEYC_F30,
|
||||
KEYC_F31,
|
||||
KEYC_F32,
|
||||
KEYC_F33,
|
||||
KEYC_F34,
|
||||
KEYC_F35,
|
||||
KEYC_IC,
|
||||
KEYC_DC,
|
||||
KEYC_HOME,
|
||||
@@ -430,54 +405,6 @@ enum {
|
||||
KEYC_KP_ENTER,
|
||||
KEYC_KP_ZERO,
|
||||
KEYC_KP_PERIOD,
|
||||
KEYC_KP_EQUAL,
|
||||
KEYC_KP_SEPARATOR,
|
||||
KEYC_KP_LEFT,
|
||||
KEYC_KP_RIGHT,
|
||||
KEYC_KP_UP,
|
||||
KEYC_KP_DOWN,
|
||||
KEYC_KP_PPAGE,
|
||||
KEYC_KP_NPAGE,
|
||||
KEYC_KP_HOME,
|
||||
KEYC_KP_END,
|
||||
KEYC_KP_IC,
|
||||
KEYC_KP_DC,
|
||||
KEYC_KP_BEGIN,
|
||||
|
||||
/* Other function keys. */
|
||||
KEYC_CAPSLOCK,
|
||||
KEYC_SCROLLLOCK,
|
||||
KEYC_NUMLOCK,
|
||||
KEYC_PRINTSCREEN,
|
||||
KEYC_PAUSE,
|
||||
KEYC_MENU,
|
||||
KEYC_MEDIA_PLAY,
|
||||
KEYC_MEDIA_PAUSE,
|
||||
KEYC_MEDIA_PLAYPAUSE,
|
||||
KEYC_MEDIA_REVERSE,
|
||||
KEYC_MEDIA_STOP,
|
||||
KEYC_MEDIA_FASTFORWARD,
|
||||
KEYC_MEDIA_REWIND,
|
||||
KEYC_MEDIA_NEXT,
|
||||
KEYC_MEDIA_PREVIOUS,
|
||||
KEYC_MEDIA_RECORD,
|
||||
KEYC_VOLUME_DOWN,
|
||||
KEYC_VOLUME_UP,
|
||||
KEYC_VOLUME_MUTE,
|
||||
KEYC_LEFT_SHIFT,
|
||||
KEYC_LEFT_CTRL,
|
||||
KEYC_LEFT_ALT,
|
||||
KEYC_LEFT_SUPER,
|
||||
KEYC_LEFT_HYPER,
|
||||
KEYC_LEFT_META,
|
||||
KEYC_RIGHT_SHIFT,
|
||||
KEYC_RIGHT_CTRL,
|
||||
KEYC_RIGHT_ALT,
|
||||
KEYC_RIGHT_SUPER,
|
||||
KEYC_RIGHT_HYPER,
|
||||
KEYC_RIGHT_META,
|
||||
KEYC_ISO_LEVEL3_SHIFT,
|
||||
KEYC_ISO_LEVEL5_SHIFT,
|
||||
|
||||
/* Theme reporting. */
|
||||
KEYC_REPORT_DARK_THEME,
|
||||
@@ -775,16 +702,6 @@ enum tty_code_code {
|
||||
#define CURSOR_MODES (MODE_CURSOR|MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)
|
||||
#define EXTENDED_KEY_MODES (MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2)
|
||||
|
||||
/* Extended key output formats. */
|
||||
#define EXTENDED_KEYS_CSI_U 0
|
||||
#define EXTENDED_KEYS_XTERM 1
|
||||
#define EXTENDED_KEYS_KITTY 2
|
||||
|
||||
/* Supported Kitty keyboard protocol flags. */
|
||||
#define KITTY_KEY_DISAMBIGUATE 0x1
|
||||
#define KITTY_KEY_REPORT_ALL 0x8
|
||||
#define KITTY_KEY_SUPPORTED (KITTY_KEY_DISAMBIGUATE|KITTY_KEY_REPORT_ALL)
|
||||
|
||||
/* Mouse protocol constants. */
|
||||
#define MOUSE_PARAM_MAX 0xff
|
||||
#define MOUSE_PARAM_UTF8_MAX 0x7ff
|
||||
@@ -1151,11 +1068,6 @@ struct progress_bar {
|
||||
/* Virtual screen. */
|
||||
struct screen_sel;
|
||||
struct screen_titles;
|
||||
struct kitty_key_state {
|
||||
u_int flags;
|
||||
u_int saved_flags;
|
||||
int have_saved;
|
||||
};
|
||||
struct screen {
|
||||
char *title;
|
||||
char *path;
|
||||
@@ -1177,8 +1089,6 @@ struct screen {
|
||||
|
||||
int mode;
|
||||
int default_mode;
|
||||
struct kitty_key_state kitty_keys;
|
||||
struct kitty_key_state saved_kitty_keys;
|
||||
|
||||
u_int saved_cx;
|
||||
u_int saved_cy;
|
||||
@@ -1240,8 +1150,7 @@ enum pane_lines {
|
||||
PANE_LINES_SIMPLE,
|
||||
PANE_LINES_NUMBER,
|
||||
PANE_LINES_SPACES,
|
||||
PANE_LINES_NONE,
|
||||
PANE_LINES_ROUNDED
|
||||
PANE_LINES_NONE
|
||||
};
|
||||
|
||||
/* Pane border indicator option. */
|
||||
@@ -1829,7 +1738,6 @@ struct tty_term {
|
||||
#define TERM_VT100LIKE 0x20
|
||||
#define TERM_SIXEL 0x40
|
||||
#define TERM_INVALIDMS 0x80
|
||||
#define TERM_KITTYKEYS 0x100
|
||||
int flags;
|
||||
|
||||
LIST_ENTRY(tty_term) entry;
|
||||
@@ -1888,7 +1796,6 @@ struct tty {
|
||||
size_t discarded;
|
||||
|
||||
struct termios tio;
|
||||
struct visible_ranges r;
|
||||
|
||||
struct grid_cell cell;
|
||||
struct grid_cell last_cell;
|
||||
@@ -1910,12 +1817,9 @@ struct tty {
|
||||
#define TTY_WAITBG 0x4000
|
||||
#define TTY_BRACKETPASTE 0x8000
|
||||
#define TTY_HAVESYNC 0x10000
|
||||
#define TTY_HAVEKKB 0x20000
|
||||
#define TTY_KKBPUSHED 0x40000
|
||||
#define TTY_ALL_REQUEST_FLAGS \
|
||||
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVESYNC|TTY_HAVEKKB)
|
||||
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVESYNC)
|
||||
int flags;
|
||||
u_int kitty_keys;
|
||||
|
||||
struct tty_term *term;
|
||||
|
||||
@@ -1953,7 +1857,6 @@ struct tty_ctx {
|
||||
#define TTY_CTX_INVISIBLE_PANES 0x2
|
||||
#define TTY_CTX_WINDOW_BIGGER 0x4
|
||||
#define TTY_CTX_SYNC 0x8
|
||||
#define TTY_CTX_OVERLAY_SYNC 0x10
|
||||
#define TTY_CTX_CELL_INVALIDATE 0x20
|
||||
#define TTY_CTX_PANE_OBSCURED 0x40
|
||||
|
||||
@@ -2288,16 +2191,6 @@ struct prompt_draw_data {
|
||||
u_int prompt_line;
|
||||
};
|
||||
|
||||
/* Overlay callbacks */
|
||||
typedef struct visible_ranges *(*overlay_check_cb)(struct client *, void *,
|
||||
u_int, u_int, u_int);
|
||||
typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *,
|
||||
u_int *);
|
||||
typedef void (*overlay_draw_cb)(struct client *, void *);
|
||||
typedef int (*overlay_key_cb)(struct client *, void *, struct key_event *);
|
||||
typedef void (*overlay_free_cb)(struct client *, void *);
|
||||
typedef void (*overlay_resize_cb)(struct client *, void *);
|
||||
|
||||
/* Client connection. */
|
||||
struct client {
|
||||
const char *name;
|
||||
@@ -2383,7 +2276,7 @@ struct client {
|
||||
#define CLIENT_SIZECHANGED 0x400000
|
||||
#define CLIENT_STATUSOFF 0x800000
|
||||
#define CLIENT_REDRAWSTATUSALWAYS 0x1000000
|
||||
#define CLIENT_REDRAWOVERLAY 0x2000000
|
||||
/* 0x2000000 unused */
|
||||
#define CLIENT_CONTROL_NOOUTPUT 0x4000000
|
||||
#define CLIENT_DEFAULTSOCKET 0x8000000
|
||||
#define CLIENT_STARTSERVER 0x10000000
|
||||
@@ -2404,7 +2297,6 @@ struct client {
|
||||
CLIENT_REDRAWSTATUS| \
|
||||
CLIENT_REDRAWSTATUSALWAYS| \
|
||||
CLIENT_REDRAWBORDERS| \
|
||||
CLIENT_REDRAWOVERLAY| \
|
||||
CLIENT_REDRAWMENU)
|
||||
#define CLIENT_UNATTACHEDFLAGS \
|
||||
(CLIENT_DEAD| \
|
||||
@@ -2450,15 +2342,6 @@ struct client {
|
||||
u_int pan_ox;
|
||||
u_int pan_oy;
|
||||
|
||||
overlay_check_cb overlay_check;
|
||||
overlay_mode_cb overlay_mode;
|
||||
overlay_draw_cb overlay_draw;
|
||||
overlay_key_cb overlay_key;
|
||||
overlay_free_cb overlay_free;
|
||||
overlay_resize_cb overlay_resize;
|
||||
void *overlay_data;
|
||||
struct event overlay_timer;
|
||||
|
||||
struct client_files files;
|
||||
u_int source_file_depth;
|
||||
|
||||
@@ -3060,15 +2943,12 @@ void tty_default_attributes(struct tty *, u_int,
|
||||
void tty_update_mode(struct tty *, int, struct screen *);
|
||||
const struct grid_cell *tty_check_codeset(struct tty *,
|
||||
const struct grid_cell *);
|
||||
struct visible_ranges *tty_check_overlay_range(struct tty *, u_int, u_int,
|
||||
u_int);
|
||||
void tty_sync_start(struct tty *);
|
||||
void tty_sync_end(struct tty *);
|
||||
int tty_open(struct tty *, char **);
|
||||
void tty_close(struct tty *);
|
||||
void tty_free(struct tty *);
|
||||
void tty_update_features(struct tty *);
|
||||
void tty_update_kitty(struct tty *, struct screen *);
|
||||
void tty_set_selection(struct tty *, const char *, const char *, size_t);
|
||||
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
|
||||
struct tty_ctx *);
|
||||
@@ -3413,14 +3293,8 @@ int server_create_socket(uint64_t, char **);
|
||||
|
||||
/* server-client.c */
|
||||
u_int server_client_how_many(void);
|
||||
void server_client_set_overlay(struct client *, u_int, overlay_check_cb,
|
||||
overlay_mode_cb, overlay_draw_cb, overlay_key_cb,
|
||||
overlay_free_cb, overlay_resize_cb, void *);
|
||||
void server_client_clear_overlay(struct client *);
|
||||
void server_client_ensure_ranges(struct visible_ranges *, u_int);
|
||||
int server_client_ranges_is_empty(struct visible_ranges *);
|
||||
void server_client_overlay_range(u_int, u_int, u_int, u_int, u_int, u_int,
|
||||
u_int, struct visible_ranges *);
|
||||
void server_client_set_key_table(struct client *, const char *);
|
||||
const char *server_client_get_key_table(struct client *);
|
||||
int server_client_check_nested(struct client *);
|
||||
@@ -3529,7 +3403,7 @@ void recalculate_sizes_now(int);
|
||||
/* input.c */
|
||||
#define INPUT_BUF_DEFAULT_SIZE 1048576
|
||||
struct input_ctx *input_init(struct window_pane *, struct bufferevent *,
|
||||
struct colour_palette *, struct client *);
|
||||
struct colour_palette *);
|
||||
void input_free(struct input_ctx *);
|
||||
void input_reset(struct input_ctx *, int);
|
||||
struct evbuffer *input_pending(struct input_ctx *);
|
||||
@@ -3550,20 +3424,6 @@ int input_key(struct screen *, struct bufferevent *, key_code);
|
||||
int input_key_get_mouse(struct screen *, struct mouse_event *, u_int,
|
||||
u_int, const char **, size_t *);
|
||||
|
||||
/* input-kitty.c */
|
||||
void input_kitty_reset(struct screen *);
|
||||
void input_kitty_alternate_on(struct screen *);
|
||||
void input_kitty_alternate_off(struct screen *);
|
||||
void input_kitty_set(struct screen *, u_int, int);
|
||||
void input_kitty_push(struct screen *, u_int);
|
||||
void input_kitty_pop(struct screen *, u_int);
|
||||
int input_key_kitty(struct screen *, struct bufferevent *, key_code);
|
||||
|
||||
/* tty-kitty.c */
|
||||
int tty_keys_kitty(struct tty *, const char *, size_t, size_t *,
|
||||
key_code *);
|
||||
int tty_keys_kitty_query(struct tty *, const char *, size_t, size_t *);
|
||||
|
||||
/* colour.c */
|
||||
int colour_find_rgb(u_char, u_char, u_char);
|
||||
int colour_join_rgb(u_char, u_char, u_char);
|
||||
@@ -4298,20 +4158,6 @@ void menu_get_cursor(struct menu_data *, u_int *, u_int *);
|
||||
void menu_resize(struct menu_data *, struct window *);
|
||||
int menu_key(struct client *, struct menu_data *, struct key_event *);
|
||||
|
||||
/* popup.c */
|
||||
#define POPUP_CLOSEEXIT 0x1
|
||||
#define POPUP_CLOSEEXITZERO 0x2
|
||||
#define POPUP_CLOSEANYKEY 0x4
|
||||
typedef void (*popup_close_cb)(int, void *);
|
||||
int popup_display(int, enum box_lines, struct cmdq_item *, u_int,
|
||||
u_int, u_int, u_int, struct environ *, const char *, int,
|
||||
char **, const char *, const char *, struct client *,
|
||||
struct session *, const char *, const char *,
|
||||
popup_close_cb, void *);
|
||||
int popup_present(struct client *);
|
||||
int popup_modify(struct client *, const char *, const char *,
|
||||
const char *, enum box_lines, int);
|
||||
|
||||
/* style.c */
|
||||
int style_parse(struct style *,const struct grid_cell *,
|
||||
const char *);
|
||||
|
||||
@@ -52,8 +52,7 @@ tty_draw_line_clear(struct tty *tty, u_int px, u_int py, u_int nx,
|
||||
return;
|
||||
|
||||
/* If genuine BCE is available, can try escape sequences. */
|
||||
if (tty->client->overlay_check == NULL &&
|
||||
!wrapped &&
|
||||
if (!wrapped &&
|
||||
nx >= 10 &&
|
||||
!tty_fake_bce(tty, defaults, bg)) {
|
||||
/* Off the end of the line, use EL if available. */
|
||||
|
||||
@@ -235,13 +235,6 @@ static const struct tty_feature tty_feature_sync = {
|
||||
0
|
||||
};
|
||||
|
||||
/* Terminal supports the Kitty keyboard protocol. */
|
||||
static const struct tty_feature tty_feature_kittykeys = {
|
||||
"kittykeys",
|
||||
NULL,
|
||||
TERM_KITTYKEYS
|
||||
};
|
||||
|
||||
/* Terminal supports extended keys. */
|
||||
static const char *const tty_feature_extkeys_capabilities[] = {
|
||||
"Eneks=\\E[>4;2m",
|
||||
@@ -393,7 +386,6 @@ static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_extkeys,
|
||||
&tty_feature_focus,
|
||||
&tty_feature_ignorefkeys,
|
||||
&tty_feature_kittykeys,
|
||||
&tty_feature_margins,
|
||||
&tty_feature_mouse,
|
||||
&tty_feature_osc7,
|
||||
|
||||
27
tty-keys.c
27
tty-keys.c
@@ -772,17 +772,6 @@ tty_keys_next(struct tty *tty)
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this a Kitty keyboard protocol response? */
|
||||
switch (tty_keys_kitty_query(tty, buf, len, &size)) {
|
||||
case 0: /* yes */
|
||||
key = KEYC_UNKNOWN;
|
||||
goto complete_key;
|
||||
case -1: /* no, or not valid */
|
||||
break;
|
||||
case 1: /* partial */
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this a synchronized update mode response? */
|
||||
switch (tty_keys_sync(tty, buf, len, &size)) {
|
||||
case 0: /* yes */
|
||||
@@ -869,18 +858,6 @@ tty_keys_next(struct tty *tty)
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this an extended key press? */
|
||||
switch (tty_keys_kitty(tty, buf, len, &size, &key)) {
|
||||
case 0: /* yes */
|
||||
goto complete_key;
|
||||
case -1: /* no, or not valid */
|
||||
break;
|
||||
case -2: /* yes, but not representable by tmux */
|
||||
goto discard_key;
|
||||
case 1: /* partial */
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this an extended key press? */
|
||||
switch (tty_keys_extended_key(tty, buf, len, &size, &key)) {
|
||||
case 0: /* yes */
|
||||
@@ -1112,8 +1089,6 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
|
||||
utf8_char uc;
|
||||
|
||||
*size = 0;
|
||||
if (tty->flags & TTY_KKBPUSHED)
|
||||
return (-1);
|
||||
|
||||
/* First two bytes are always \033[. */
|
||||
if (buf[0] != '\033')
|
||||
@@ -1552,8 +1527,6 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
|
||||
}
|
||||
log_debug("%s: received primary DA %.*s", c->name, (int)*size, buf);
|
||||
|
||||
/* A DA response without a preceding keyboard response means no support. */
|
||||
tty->flags |= TTY_HAVEKKB;
|
||||
tty_update_features(tty);
|
||||
tty->flags |= TTY_HAVEDA;
|
||||
|
||||
|
||||
430
tty-kitty.c
430
tty-kitty.c
@@ -1,430 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Michael Grant <mgrant@grant.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Detect support in the outside terminal and decode its key sequences. */
|
||||
|
||||
struct tty_kitty_key {
|
||||
u_int number;
|
||||
key_code key;
|
||||
};
|
||||
|
||||
static const struct tty_kitty_key tty_kitty_keys[] = {
|
||||
{ 57358, KEYC_CAPSLOCK },
|
||||
{ 57359, KEYC_SCROLLLOCK },
|
||||
{ 57360, KEYC_NUMLOCK },
|
||||
{ 57361, KEYC_PRINTSCREEN },
|
||||
{ 57362, KEYC_PAUSE },
|
||||
{ 57363, KEYC_MENU },
|
||||
{ 57376, KEYC_F13 },
|
||||
{ 57377, KEYC_F14 },
|
||||
{ 57378, KEYC_F15 },
|
||||
{ 57379, KEYC_F16 },
|
||||
{ 57380, KEYC_F17 },
|
||||
{ 57381, KEYC_F18 },
|
||||
{ 57382, KEYC_F19 },
|
||||
{ 57383, KEYC_F20 },
|
||||
{ 57384, KEYC_F21 },
|
||||
{ 57385, KEYC_F22 },
|
||||
{ 57386, KEYC_F23 },
|
||||
{ 57387, KEYC_F24 },
|
||||
{ 57388, KEYC_F25 },
|
||||
{ 57389, KEYC_F26 },
|
||||
{ 57390, KEYC_F27 },
|
||||
{ 57391, KEYC_F28 },
|
||||
{ 57392, KEYC_F29 },
|
||||
{ 57393, KEYC_F30 },
|
||||
{ 57394, KEYC_F31 },
|
||||
{ 57395, KEYC_F32 },
|
||||
{ 57396, KEYC_F33 },
|
||||
{ 57397, KEYC_F34 },
|
||||
{ 57398, KEYC_F35 },
|
||||
{ 57399, KEYC_KP_ZERO|KEYC_KEYPAD },
|
||||
{ 57400, KEYC_KP_ONE|KEYC_KEYPAD },
|
||||
{ 57401, KEYC_KP_TWO|KEYC_KEYPAD },
|
||||
{ 57402, KEYC_KP_THREE|KEYC_KEYPAD },
|
||||
{ 57403, KEYC_KP_FOUR|KEYC_KEYPAD },
|
||||
{ 57404, KEYC_KP_FIVE|KEYC_KEYPAD },
|
||||
{ 57405, KEYC_KP_SIX|KEYC_KEYPAD },
|
||||
{ 57406, KEYC_KP_SEVEN|KEYC_KEYPAD },
|
||||
{ 57407, KEYC_KP_EIGHT|KEYC_KEYPAD },
|
||||
{ 57408, KEYC_KP_NINE|KEYC_KEYPAD },
|
||||
{ 57409, KEYC_KP_PERIOD|KEYC_KEYPAD },
|
||||
{ 57410, KEYC_KP_SLASH|KEYC_KEYPAD },
|
||||
{ 57411, KEYC_KP_STAR|KEYC_KEYPAD },
|
||||
{ 57412, KEYC_KP_MINUS|KEYC_KEYPAD },
|
||||
{ 57413, KEYC_KP_PLUS|KEYC_KEYPAD },
|
||||
{ 57414, KEYC_KP_ENTER|KEYC_KEYPAD },
|
||||
{ 57415, KEYC_KP_EQUAL|KEYC_KEYPAD },
|
||||
{ 57416, KEYC_KP_SEPARATOR|KEYC_KEYPAD },
|
||||
{ 57417, KEYC_KP_LEFT|KEYC_KEYPAD },
|
||||
{ 57418, KEYC_KP_RIGHT|KEYC_KEYPAD },
|
||||
{ 57419, KEYC_KP_UP|KEYC_KEYPAD },
|
||||
{ 57420, KEYC_KP_DOWN|KEYC_KEYPAD },
|
||||
{ 57421, KEYC_KP_PPAGE|KEYC_KEYPAD },
|
||||
{ 57422, KEYC_KP_NPAGE|KEYC_KEYPAD },
|
||||
{ 57423, KEYC_KP_HOME|KEYC_KEYPAD },
|
||||
{ 57424, KEYC_KP_END|KEYC_KEYPAD },
|
||||
{ 57425, KEYC_KP_IC|KEYC_KEYPAD },
|
||||
{ 57426, KEYC_KP_DC|KEYC_KEYPAD },
|
||||
{ 57427, KEYC_KP_BEGIN|KEYC_KEYPAD },
|
||||
{ 57428, KEYC_MEDIA_PLAY },
|
||||
{ 57429, KEYC_MEDIA_PAUSE },
|
||||
{ 57430, KEYC_MEDIA_PLAYPAUSE },
|
||||
{ 57431, KEYC_MEDIA_REVERSE },
|
||||
{ 57432, KEYC_MEDIA_STOP },
|
||||
{ 57433, KEYC_MEDIA_FASTFORWARD },
|
||||
{ 57434, KEYC_MEDIA_REWIND },
|
||||
{ 57435, KEYC_MEDIA_NEXT },
|
||||
{ 57436, KEYC_MEDIA_PREVIOUS },
|
||||
{ 57437, KEYC_MEDIA_RECORD },
|
||||
{ 57438, KEYC_VOLUME_DOWN },
|
||||
{ 57439, KEYC_VOLUME_UP },
|
||||
{ 57440, KEYC_VOLUME_MUTE },
|
||||
{ 57441, KEYC_LEFT_SHIFT },
|
||||
{ 57442, KEYC_LEFT_CTRL },
|
||||
{ 57443, KEYC_LEFT_ALT },
|
||||
{ 57444, KEYC_LEFT_SUPER },
|
||||
{ 57445, KEYC_LEFT_HYPER },
|
||||
{ 57446, KEYC_LEFT_META },
|
||||
{ 57447, KEYC_RIGHT_SHIFT },
|
||||
{ 57448, KEYC_RIGHT_CTRL },
|
||||
{ 57449, KEYC_RIGHT_ALT },
|
||||
{ 57450, KEYC_RIGHT_SUPER },
|
||||
{ 57451, KEYC_RIGHT_HYPER },
|
||||
{ 57452, KEYC_RIGHT_META },
|
||||
{ 57453, KEYC_ISO_LEVEL3_SHIFT },
|
||||
{ 57454, KEYC_ISO_LEVEL5_SHIFT }
|
||||
};
|
||||
|
||||
static int
|
||||
tty_kitty_parse_number(const char *s, u_int *value, int empty)
|
||||
{
|
||||
char *end;
|
||||
unsigned long number;
|
||||
|
||||
if (*s == '\0') {
|
||||
if (!empty)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
if (!isdigit((u_char)*s))
|
||||
return (-1);
|
||||
number = strtoul(s, &end, 10);
|
||||
if (*end != '\0' || number > UINT_MAX)
|
||||
return (-1);
|
||||
*value = number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
tty_kitty_parse_list(char *s, u_int *first, u_int *second, int empty,
|
||||
u_int maximum)
|
||||
{
|
||||
char *copy, *item;
|
||||
u_int n = 0, value;
|
||||
int result = 0;
|
||||
|
||||
copy = s;
|
||||
while ((item = strsep(©, ":")) != NULL) {
|
||||
if (maximum != 0 && n == maximum)
|
||||
return (-1);
|
||||
value = 0;
|
||||
if (tty_kitty_parse_number(item, &value, empty) != 0) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
if (n == 0 && *item != '\0')
|
||||
*first = value;
|
||||
else if (n == 1 && *item != '\0')
|
||||
*second = value;
|
||||
n++;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
tty_kitty_find_end(const char *buf, size_t len, size_t *end)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 2; i < len; i++) {
|
||||
if (buf[i] == 'u' || buf[i] == '~' || buf[i] == 'A' ||
|
||||
buf[i] == 'B' || buf[i] == 'C' || buf[i] == 'D' ||
|
||||
buf[i] == 'E' || buf[i] == 'F' || buf[i] == 'H' ||
|
||||
buf[i] == 'P' || buf[i] == 'Q' || buf[i] == 'S') {
|
||||
*end = i;
|
||||
return (0);
|
||||
}
|
||||
if (!isdigit((u_char)buf[i]) && buf[i] != ';' && buf[i] != ':')
|
||||
return (-1);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
static key_code
|
||||
tty_kitty_function(u_int number, char final)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (final == 'u') {
|
||||
switch (number) {
|
||||
case 9:
|
||||
return (C0_HT);
|
||||
case 13:
|
||||
return (C0_CR);
|
||||
case 27:
|
||||
return (C0_ESC);
|
||||
case 127:
|
||||
return (KEYC_BSPACE);
|
||||
}
|
||||
for (i = 0; i < nitems(tty_kitty_keys); i++) {
|
||||
if (tty_kitty_keys[i].number == number)
|
||||
return (tty_kitty_keys[i].key);
|
||||
}
|
||||
return (KEYC_NONE);
|
||||
}
|
||||
|
||||
if (final == '~') {
|
||||
switch (number) {
|
||||
case 2: return (KEYC_IC);
|
||||
case 3: return (KEYC_DC);
|
||||
case 5: return (KEYC_PPAGE);
|
||||
case 6: return (KEYC_NPAGE);
|
||||
case 7: return (KEYC_HOME);
|
||||
case 8: return (KEYC_END);
|
||||
case 11: return (KEYC_F1);
|
||||
case 12: return (KEYC_F2);
|
||||
case 13: return (KEYC_F3);
|
||||
case 14: return (KEYC_F4);
|
||||
case 15: return (KEYC_F5);
|
||||
case 17: return (KEYC_F6);
|
||||
case 18: return (KEYC_F7);
|
||||
case 19: return (KEYC_F8);
|
||||
case 20: return (KEYC_F9);
|
||||
case 21: return (KEYC_F10);
|
||||
case 23: return (KEYC_F11);
|
||||
case 24: return (KEYC_F12);
|
||||
case 29: return (KEYC_MENU);
|
||||
case 57427: return (KEYC_KP_BEGIN|KEYC_KEYPAD);
|
||||
}
|
||||
return (KEYC_UNKNOWN);
|
||||
}
|
||||
if (number != 1)
|
||||
return (KEYC_UNKNOWN);
|
||||
switch (final) {
|
||||
case 'A': return (KEYC_UP|KEYC_CURSOR);
|
||||
case 'B': return (KEYC_DOWN|KEYC_CURSOR);
|
||||
case 'C': return (KEYC_RIGHT|KEYC_CURSOR);
|
||||
case 'D': return (KEYC_LEFT|KEYC_CURSOR);
|
||||
case 'E': return (KEYC_KP_BEGIN|KEYC_KEYPAD);
|
||||
case 'F': return (KEYC_END);
|
||||
case 'H': return (KEYC_HOME);
|
||||
case 'P': return (KEYC_F1);
|
||||
case 'Q': return (KEYC_F2);
|
||||
case 'S': return (KEYC_F4);
|
||||
}
|
||||
return (KEYC_UNKNOWN);
|
||||
}
|
||||
|
||||
int
|
||||
tty_keys_kitty_query(struct tty *tty, const char *buf, size_t len,
|
||||
size_t *size)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
size_t i;
|
||||
u_int flags = 0;
|
||||
|
||||
*size = 0;
|
||||
if (tty->flags & TTY_HAVEKKB)
|
||||
return (-1);
|
||||
|
||||
if (buf[0] != '\033')
|
||||
return (-1);
|
||||
if (len == 1)
|
||||
return (1);
|
||||
if (buf[1] != '[')
|
||||
return (-1);
|
||||
if (len == 2)
|
||||
return (1);
|
||||
if (buf[2] != '?')
|
||||
return (-1);
|
||||
if (len == 3)
|
||||
return (1);
|
||||
|
||||
for (i = 3; i < len && isdigit((u_char)buf[i]); i++) {
|
||||
if (flags > (UINT_MAX - (buf[i] - '0')) / 10)
|
||||
return (-1);
|
||||
flags = (flags * 10) + (buf[i] - '0');
|
||||
}
|
||||
if (i == len)
|
||||
return (1);
|
||||
if (i == 3 || buf[i] != 'u')
|
||||
return (-1);
|
||||
|
||||
*size = i + 1;
|
||||
tty->kitty_keys = flags;
|
||||
tty->flags |= TTY_HAVEKKB;
|
||||
log_debug("%s: received Kitty keyboard flags %u", c->name, flags);
|
||||
tty_parse_client_features(c, "kittykeys", ",");
|
||||
tty_update_features(tty);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
tty_update_kitty(struct tty *tty, struct screen *s)
|
||||
{
|
||||
u_int flags;
|
||||
char buf[32];
|
||||
|
||||
if (options_get_number(global_options, "extended-keys") == 0 ||
|
||||
(~tty->term->flags & TERM_KITTYKEYS)) {
|
||||
if (tty->flags & TTY_KKBPUSHED) {
|
||||
tty_puts(tty, "\033[<u");
|
||||
tty->flags &= ~TTY_KKBPUSHED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
flags = KITTY_KEY_DISAMBIGUATE;
|
||||
if (s != NULL && (s->kitty_keys.flags & KITTY_KEY_SUPPORTED) != 0)
|
||||
flags = s->kitty_keys.flags & KITTY_KEY_SUPPORTED;
|
||||
if ((tty->flags & TTY_KKBPUSHED) == 0) {
|
||||
xsnprintf(buf, sizeof buf, "\033[>%uu", flags);
|
||||
tty_puts(tty, buf);
|
||||
tty->flags |= TTY_KKBPUSHED;
|
||||
} else if (tty->kitty_keys != flags) {
|
||||
xsnprintf(buf, sizeof buf, "\033[=%uu", flags);
|
||||
tty_puts(tty, buf);
|
||||
}
|
||||
tty->kitty_keys = flags;
|
||||
}
|
||||
|
||||
int
|
||||
tty_keys_kitty(struct tty *tty, const char *buf, size_t len, size_t *size,
|
||||
key_code *key)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
struct utf8_data ud;
|
||||
utf8_char uc;
|
||||
size_t end;
|
||||
char tmp[128], *copy, *field, final;
|
||||
u_int number = 0, modifiers = 1, event = 1, value;
|
||||
u_int fields = 0;
|
||||
key_code nkey, onlykey;
|
||||
int result;
|
||||
|
||||
*size = 0;
|
||||
if ((tty->flags & TTY_KKBPUSHED) == 0)
|
||||
return (-1);
|
||||
if (len == 0 || buf[0] != '\033')
|
||||
return (-1);
|
||||
if (len == 1)
|
||||
return (1);
|
||||
if (buf[1] != '[')
|
||||
return (-1);
|
||||
if (len == 2)
|
||||
return (1);
|
||||
if (buf[2] == '?')
|
||||
return (-1);
|
||||
|
||||
result = tty_kitty_find_end(buf, len, &end);
|
||||
if (result != 0)
|
||||
return (result);
|
||||
if (end - 2 >= sizeof tmp)
|
||||
return (-1);
|
||||
memcpy(tmp, buf + 2, end - 2);
|
||||
tmp[end - 2] = '\0';
|
||||
final = buf[end];
|
||||
*size = end + 1;
|
||||
|
||||
copy = tmp;
|
||||
while ((field = strsep(©, ";")) != NULL) {
|
||||
if (fields == 3)
|
||||
return (-1);
|
||||
value = 0;
|
||||
if (fields == 0) {
|
||||
if (*field == '\0') {
|
||||
if (final == 'u')
|
||||
return (-1);
|
||||
number = 1;
|
||||
} else if (tty_kitty_parse_list(field, &number, &value,
|
||||
1, 3) != 0)
|
||||
return (-1);
|
||||
} else if (fields == 1) {
|
||||
if (tty_kitty_parse_list(field, &modifiers, &event, 1,
|
||||
2) != 0)
|
||||
return (-1);
|
||||
} else if (tty_kitty_parse_list(field, &value, &value, 1, 0) != 0)
|
||||
return (-1);
|
||||
fields++;
|
||||
}
|
||||
if (fields == 0 || number == 0 || modifiers == 0)
|
||||
return (-1);
|
||||
if (event == 0 || event == 3 || event > 3)
|
||||
return (-2);
|
||||
|
||||
modifiers--;
|
||||
if (modifiers & 32)
|
||||
return (-2);
|
||||
nkey = tty_kitty_function(number, final);
|
||||
if (nkey == KEYC_NONE) {
|
||||
if (final != 'u')
|
||||
return (-1);
|
||||
if (number >= 57344 && number <= 63743)
|
||||
return (-2);
|
||||
if (number <= 0x7f)
|
||||
nkey = number;
|
||||
else if (utf8_fromwc(number, &ud) != UTF8_DONE ||
|
||||
utf8_from_data(&ud, &uc) != UTF8_DONE)
|
||||
return (-2);
|
||||
else
|
||||
nkey = uc;
|
||||
} else if (nkey == KEYC_UNKNOWN)
|
||||
return (-1);
|
||||
|
||||
if (modifiers & 1)
|
||||
nkey |= KEYC_SHIFT;
|
||||
if (modifiers & 2)
|
||||
nkey |= KEYC_META|KEYC_IMPLIED_META;
|
||||
if (modifiers & 4)
|
||||
nkey |= KEYC_CTRL;
|
||||
if (modifiers & 8)
|
||||
nkey |= KEYC_SUPER;
|
||||
if (modifiers & 16)
|
||||
nkey |= KEYC_HYPER;
|
||||
|
||||
/* Shift-Tab has a dedicated tmux key code. */
|
||||
onlykey = nkey & KEYC_MASK_KEY;
|
||||
if (onlykey == C0_HT && (nkey & KEYC_SHIFT))
|
||||
nkey = KEYC_BTAB|(nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT);
|
||||
|
||||
if (log_get_level() != 0) {
|
||||
log_debug("%s: Kitty key %.*s is %llx (%s)", c->name,
|
||||
(int)*size, buf, nkey, key_string_lookup_key(nkey, 1));
|
||||
}
|
||||
*key = nkey;
|
||||
return (0);
|
||||
}
|
||||
232
tty.c
232
tty.c
@@ -66,7 +66,6 @@ static void tty_redraw_region(struct tty *, const struct tty_ctx *);
|
||||
static void tty_emulate_repeat(struct tty *, enum tty_code_code,
|
||||
enum tty_code_code, u_int);
|
||||
static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
|
||||
static int tty_check_overlay(struct tty *, u_int, u_int);
|
||||
|
||||
#ifdef ENABLE_SIXEL
|
||||
static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *),
|
||||
@@ -409,8 +408,6 @@ tty_send_requests(struct tty *tty)
|
||||
return;
|
||||
|
||||
if (tty->term->flags & TERM_VT100LIKE) {
|
||||
if (~tty->flags & TTY_HAVEKKB)
|
||||
tty_puts(tty, "\033[?u");
|
||||
if (~tty->flags & TTY_HAVEDA)
|
||||
tty_puts(tty, "\033[c");
|
||||
if (~tty->flags & TTY_HAVEDA2)
|
||||
@@ -509,10 +506,6 @@ tty_stop_tty(struct tty *tty)
|
||||
tty_raw(tty, "\033[?7727l");
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSFCS));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSEKS));
|
||||
if (tty->flags & TTY_KKBPUSHED) {
|
||||
tty_raw(tty, "\033[<u");
|
||||
tty->flags &= ~TTY_KKBPUSHED;
|
||||
}
|
||||
|
||||
if (tty_use_margin(tty))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
|
||||
@@ -551,8 +544,6 @@ void
|
||||
tty_free(struct tty *tty)
|
||||
{
|
||||
tty_close(tty);
|
||||
|
||||
free(tty->r.ranges);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -565,12 +556,8 @@ tty_update_features(struct tty *tty)
|
||||
|
||||
if (tty_use_margin(tty))
|
||||
tty_putcode(tty, TTYC_ENMG);
|
||||
if (options_get_number(global_options, "extended-keys") == 0 ||
|
||||
(tty->term->flags & TERM_KITTYKEYS))
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_DSEKS));
|
||||
else
|
||||
if (options_get_number(global_options, "extended-keys"))
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_ENEKS));
|
||||
tty_update_kitty(tty, NULL);
|
||||
if (options_get_number(global_options, "focus-events"))
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_ENFCS));
|
||||
if (tty->term->flags & TERM_VT100LIKE)
|
||||
@@ -1211,9 +1198,6 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
|
||||
u_int px, u_int nx, u_int bg)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *rr;
|
||||
u_int i;
|
||||
|
||||
log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
|
||||
|
||||
@@ -1222,7 +1206,7 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
|
||||
return;
|
||||
|
||||
/* If genuine BCE is available, can try escape sequences. */
|
||||
if (c->overlay_check == NULL && !tty_fake_bce(tty, defaults, bg)) {
|
||||
if (!tty_fake_bce(tty, defaults, bg)) {
|
||||
/* Off the end of the line, use EL if available. */
|
||||
if (px + nx >= tty->sx && tty_term_has(tty->term, TTYC_EL)) {
|
||||
tty_cursor(tty, px, py);
|
||||
@@ -1245,18 +1229,9 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Couldn't use an escape sequence, use spaces. Clear only the visible
|
||||
* bit if there is an overlay.
|
||||
*/
|
||||
r = tty_check_overlay_range(tty, px, py, nx);
|
||||
for (i = 0; i < r->used; i++) {
|
||||
rr = &r->ranges[i];
|
||||
if (rr->nx != 0) {
|
||||
tty_cursor(tty, rr->px, py);
|
||||
tty_repeat_space(tty, rr->nx);
|
||||
}
|
||||
}
|
||||
/* Couldn't use an escape sequence, use spaces. */
|
||||
tty_cursor(tty, px, py);
|
||||
tty_repeat_space(tty, nx);
|
||||
}
|
||||
|
||||
/* Clear a line, adjusting to visible part of pane. */
|
||||
@@ -1265,22 +1240,12 @@ tty_clear_pane_line(struct tty *tty, const struct tty_ctx *ctx, u_int py,
|
||||
u_int px, u_int nx, u_int bg)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *ri;
|
||||
u_int i, l, x, rx, ry;
|
||||
u_int l, x, rx, ry;
|
||||
|
||||
log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
|
||||
|
||||
if (tty_clamp_line(tty, ctx, px, py, nx, &l, &x, &rx, &ry)) {
|
||||
r = tty_check_overlay_range(tty, x, ry, rx);
|
||||
for (i = 0; i < r->used; i++) {
|
||||
ri = &r->ranges[i];
|
||||
if (ri->nx == 0)
|
||||
continue;
|
||||
tty_clear_line(tty, &ctx->defaults, ry, ri->px, ri->nx,
|
||||
bg);
|
||||
}
|
||||
}
|
||||
if (tty_clamp_line(tty, ctx, px, py, nx, &l, &x, &rx, &ry))
|
||||
tty_clear_line(tty, &ctx->defaults, ry, x, rx, bg);
|
||||
}
|
||||
|
||||
/* Clamp area position to visible part of pane. */
|
||||
@@ -1361,11 +1326,8 @@ tty_clear_area(struct tty *tty, const struct tty_ctx *ctx, u_int py,
|
||||
if (nx == 0 || ny == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If there is an overlay or BCE is not available, cannot clear as a
|
||||
* region.
|
||||
*/
|
||||
if (c->overlay_check == NULL && !tty_fake_bce(tty, defaults, bg)) {
|
||||
/* If BCE is available, can try to clear as a region. */
|
||||
if (!tty_fake_bce(tty, defaults, bg)) {
|
||||
/* Use ED if clearing off the bottom of the terminal. */
|
||||
if (px == 0 &&
|
||||
px + nx >= tty->sx &&
|
||||
@@ -1437,53 +1399,28 @@ static void
|
||||
tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
|
||||
{
|
||||
struct screen *s = ctx->s;
|
||||
u_int nx = ctx->sx, i, x, rx, ry, j;
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *rr;
|
||||
u_int nx = ctx->sx, i, x, rx, ry;
|
||||
|
||||
log_debug("%s: %s %u", __func__, tty->client->name, py);
|
||||
|
||||
if (~ctx->flags & TTY_CTX_WINDOW_BIGGER) {
|
||||
r = tty_check_overlay_range(tty, ctx->xoff, ctx->yoff + py, nx);
|
||||
for (j = 0; j < r->used; j++) {
|
||||
rr = &r->ranges[j];
|
||||
if (rr->nx == 0)
|
||||
continue;
|
||||
tty_draw_line(tty, s, rr->px - ctx->xoff, py, rr->nx,
|
||||
rr->px, ctx->yoff + py, &ctx->style_ctx);
|
||||
}
|
||||
tty_draw_line(tty, s, 0, py, nx, ctx->xoff, ctx->yoff + py,
|
||||
&ctx->style_ctx);
|
||||
return;
|
||||
}
|
||||
if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry)) {
|
||||
r = tty_check_overlay_range(tty, x, ry, rx);
|
||||
for (j = 0; j < r->used; j++) {
|
||||
rr = &r->ranges[j];
|
||||
if (rr->nx == 0)
|
||||
continue;
|
||||
tty_draw_line(tty, s, i + rr->px - x, py, rr->nx,
|
||||
rr->px, ry, &ctx->style_ctx);
|
||||
}
|
||||
}
|
||||
if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry))
|
||||
tty_draw_line(tty, s, i, py, rx, x, ry, &ctx->style_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
tty_cmd_redrawline(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
u_int i, x, rx, ry, j;
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *rr;
|
||||
u_int i, x, rx, ry;
|
||||
|
||||
if (tty_clamp_line(tty, ctx, ctx->ocx, ctx->ocy, ctx->n,
|
||||
&i, &x, &rx, &ry)) {
|
||||
r = tty_check_overlay_range(tty, x, ry, rx);
|
||||
for (j = 0; j < r->used; j++) {
|
||||
rr = &r->ranges[j];
|
||||
if (rr->nx == 0)
|
||||
continue;
|
||||
tty_draw_line(tty, ctx->s, ctx->ocx + i + rr->px - x,
|
||||
ctx->ocy, rr->nx, rr->px, ry, &ctx->style_ctx);
|
||||
}
|
||||
}
|
||||
&i, &x, &rx, &ry))
|
||||
tty_draw_line(tty, ctx->s, ctx->ocx + i, ctx->ocy, rx, x, ry,
|
||||
&ctx->style_ctx);
|
||||
}
|
||||
|
||||
/* Check if character needs to be mapped for codeset. */
|
||||
@@ -1520,36 +1457,6 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
|
||||
return (&new);
|
||||
}
|
||||
|
||||
/* Check if a single character is covered by the overlay. */
|
||||
static int
|
||||
tty_check_overlay(struct tty *tty, u_int px, u_int py)
|
||||
{
|
||||
struct visible_ranges *r;
|
||||
|
||||
/*
|
||||
* With a single character, if there is anything visible (that is, the
|
||||
* range is not empty), it must be that character.
|
||||
*/
|
||||
r = tty_check_overlay_range(tty, px, py, 1);
|
||||
return (!server_client_ranges_is_empty(r));
|
||||
}
|
||||
|
||||
/* Return parts of the input range which are visible. */
|
||||
struct visible_ranges *
|
||||
tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if (c->overlay_check == NULL) {
|
||||
server_client_ensure_ranges(&tty->r, 1);
|
||||
tty->r.ranges[0].px = px;
|
||||
tty->r.ranges[0].nx = nx;
|
||||
tty->r.used = 1;
|
||||
return (&tty->r);
|
||||
}
|
||||
return (c->overlay_check(c, c->overlay_data, px, py, nx));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL
|
||||
/* Update context for client. */
|
||||
static int
|
||||
@@ -1693,14 +1600,11 @@ tty_write_one(void (*cmdfn)(struct tty *, const struct tty_ctx *),
|
||||
void
|
||||
tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) ||
|
||||
!tty_full_width(tty, ctx) ||
|
||||
tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
|
||||
(!tty_term_has(tty->term, TTYC_ICH) &&
|
||||
!tty_term_has(tty->term, TTYC_ICH1)) ||
|
||||
c->overlay_check != NULL) {
|
||||
!tty_term_has(tty->term, TTYC_ICH1))) {
|
||||
tty_draw_pane(tty, ctx, ctx->ocy);
|
||||
return;
|
||||
}
|
||||
@@ -1715,14 +1619,11 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) ||
|
||||
!tty_full_width(tty, ctx) ||
|
||||
tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
|
||||
(!tty_term_has(tty->term, TTYC_DCH) &&
|
||||
!tty_term_has(tty->term, TTYC_DCH1)) ||
|
||||
c->overlay_check != NULL) {
|
||||
!tty_term_has(tty->term, TTYC_DCH1))) {
|
||||
tty_draw_pane(tty, ctx, ctx->ocy);
|
||||
return;
|
||||
}
|
||||
@@ -1745,16 +1646,13 @@ tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) ||
|
||||
!tty_full_width(tty, ctx) ||
|
||||
tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
|
||||
!tty_term_has(tty->term, TTYC_CSR) ||
|
||||
!tty_term_has(tty->term, TTYC_IL1) ||
|
||||
ctx->sx == 1 ||
|
||||
ctx->sy == 1 ||
|
||||
c->overlay_check != NULL) {
|
||||
ctx->sy == 1) {
|
||||
tty_redraw_region(tty, ctx);
|
||||
return;
|
||||
}
|
||||
@@ -1772,16 +1670,13 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) ||
|
||||
!tty_full_width(tty, ctx) ||
|
||||
tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
|
||||
!tty_term_has(tty->term, TTYC_CSR) ||
|
||||
!tty_term_has(tty->term, TTYC_DL1) ||
|
||||
ctx->sx == 1 ||
|
||||
ctx->sy == 1 ||
|
||||
c->overlay_check != NULL) {
|
||||
ctx->sy == 1) {
|
||||
tty_redraw_region(tty, ctx);
|
||||
return;
|
||||
}
|
||||
@@ -1825,8 +1720,6 @@ tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if (ctx->ocy != ctx->orupper)
|
||||
return;
|
||||
|
||||
@@ -1837,8 +1730,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
|
||||
(!tty_term_has(tty->term, TTYC_RI) &&
|
||||
!tty_term_has(tty->term, TTYC_RIN)) ||
|
||||
ctx->sx == 1 ||
|
||||
ctx->sy == 1 ||
|
||||
c->overlay_check != NULL) {
|
||||
ctx->sy == 1) {
|
||||
tty_redraw_region(tty, ctx);
|
||||
return;
|
||||
}
|
||||
@@ -1858,8 +1750,6 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if (ctx->ocy != ctx->orlower)
|
||||
return;
|
||||
|
||||
@@ -1868,8 +1758,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
|
||||
tty_fake_bce(tty, &ctx->defaults, 8) ||
|
||||
!tty_term_has(tty->term, TTYC_CSR) ||
|
||||
ctx->sx == 1 ||
|
||||
ctx->sy == 1 ||
|
||||
c->overlay_check != NULL) {
|
||||
ctx->sy == 1) {
|
||||
tty_redraw_region(tty, ctx);
|
||||
return;
|
||||
}
|
||||
@@ -1900,7 +1789,6 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
u_int i;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) ||
|
||||
@@ -1908,8 +1796,7 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
|
||||
tty_fake_bce(tty, &ctx->defaults, 8) ||
|
||||
!tty_term_has(tty->term, TTYC_CSR) ||
|
||||
ctx->sx == 1 ||
|
||||
ctx->sy == 1 ||
|
||||
c->overlay_check != NULL) {
|
||||
ctx->sy == 1) {
|
||||
tty_redraw_region(tty, ctx);
|
||||
return;
|
||||
}
|
||||
@@ -1939,7 +1826,6 @@ void
|
||||
tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
u_int i;
|
||||
struct client *c = tty->client;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) ||
|
||||
(!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
|
||||
@@ -1948,8 +1834,7 @@ tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx)
|
||||
(!tty_term_has(tty->term, TTYC_RI) &&
|
||||
!tty_term_has(tty->term, TTYC_RIN)) ||
|
||||
ctx->sx == 1 ||
|
||||
ctx->sy == 1 ||
|
||||
c->overlay_check != NULL) {
|
||||
ctx->sy == 1) {
|
||||
tty_redraw_region(tty, ctx);
|
||||
return;
|
||||
}
|
||||
@@ -2037,11 +1922,9 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
u_int i, j;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) ||
|
||||
c->overlay_check != NULL) {
|
||||
if (ctx->flags & TTY_CTX_WINDOW_BIGGER) {
|
||||
ctx->redraw_cb(ctx);
|
||||
return;
|
||||
}
|
||||
@@ -2061,29 +1944,9 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
const struct grid_cell *gcp = ctx->cell;
|
||||
struct screen *s = ctx->s;
|
||||
struct visible_ranges *r;
|
||||
u_int px, py, i, vis = 0;
|
||||
|
||||
px = ctx->xoff + ctx->ocx - ctx->wox;
|
||||
py = ctx->yoff + ctx->ocy - ctx->woy;
|
||||
if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, 1, 1))
|
||||
return;
|
||||
|
||||
if (gcp->data.width == 1 && !tty_check_overlay(tty, px, py))
|
||||
return;
|
||||
if (gcp->data.width > 1) { /* could be partially obscured */
|
||||
r = tty_check_overlay_range(tty, px, py, gcp->data.width);
|
||||
for (i = 0; i < r->used; i++)
|
||||
vis += r->ranges[i].nx;
|
||||
if (vis < gcp->data.width) {
|
||||
tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width,
|
||||
px, py, &ctx->style_ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->xoff + ctx->ocx - ctx->wox > tty->sx - 1 &&
|
||||
ctx->ocy == ctx->orlower &&
|
||||
tty_full_width(tty, ctx))
|
||||
@@ -2103,9 +1966,6 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *ri;
|
||||
u_int i, px, py, cx;
|
||||
const char *cp = ctx->data.data;
|
||||
size_t n = ctx->data.size;
|
||||
|
||||
@@ -2131,20 +1991,7 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
|
||||
tty_margin_off(tty);
|
||||
tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
|
||||
tty_attributes(tty, ctx->cell, &ctx->style_ctx);
|
||||
|
||||
/* Get tty position from pane position for overlay check. */
|
||||
px = ctx->xoff + ctx->ocx - ctx->wox;
|
||||
py = ctx->yoff + ctx->ocy - ctx->woy;
|
||||
|
||||
r = tty_check_overlay_range(tty, px, py, n);
|
||||
for (i = 0; i < r->used; i++) {
|
||||
ri = &r->ranges[i];
|
||||
if (ri->nx != 0) {
|
||||
cx = ri->px - ctx->xoff + ctx->wox;
|
||||
tty_cursor_pane_unless_wrap(tty, ctx, cx, ctx->ocy);
|
||||
tty_putn(tty, cp + ri->px - px, ri->nx, ri->nx);
|
||||
}
|
||||
}
|
||||
tty_putn(tty, cp, n, n);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2238,23 +2085,8 @@ tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
|
||||
if ((ctx->flags & TTY_CTX_OVERLAY_SYNC) &&
|
||||
(ctx->flags & TTY_CTX_SYNC)) {
|
||||
/*
|
||||
* This is an overlay and a command that moves the cursor so
|
||||
* start synchronized updates.
|
||||
*/
|
||||
if (ctx->flags & TTY_CTX_SYNC)
|
||||
tty_sync_start(tty);
|
||||
} else if (~ctx->flags & TTY_CTX_OVERLAY_SYNC) {
|
||||
/*
|
||||
* This is a pane. If there is an overlay, always start;
|
||||
* otherwise, only if requested.
|
||||
*/
|
||||
if ((ctx->flags & TTY_CTX_SYNC) || c->overlay_draw != NULL)
|
||||
tty_sync_start(tty);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2273,10 +2105,6 @@ tty_cell(struct tty *tty, const struct grid_cell *gc,
|
||||
if (gc->flags & GRID_FLAG_PADDING)
|
||||
return;
|
||||
|
||||
/* Check if character is covered by overlay or floating pane. */
|
||||
if (!tty_check_overlay(tty, tty->cx, tty->cy))
|
||||
return;
|
||||
|
||||
/* Check the output codeset and apply attributes. */
|
||||
gcp = tty_check_codeset(tty, gc);
|
||||
tty_attributes(tty, gcp, style_ctx);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-border.c,v 1.4 2026/09/11 10:17:16 nicm Exp $ */
|
||||
/* $OpenBSD: window-border.c,v 1.3 2026/07/23 09:38:27 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -120,10 +120,6 @@ window_get_border_cell(struct window_pane *wp, enum pane_lines pane_lines,
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
|
||||
break;
|
||||
case PANE_LINES_ROUNDED:
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type));
|
||||
break;
|
||||
case PANE_LINES_SIMPLE:
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
|
||||
|
||||
@@ -665,7 +665,7 @@ window_copy_view_init(struct window_mode_entry *wme,
|
||||
|
||||
data->backing = xmalloc(sizeof *data->backing);
|
||||
screen_init(data->backing, sx, screen_size_y(base), UINT_MAX);
|
||||
data->ictx = input_init(NULL, NULL, NULL, NULL);
|
||||
data->ictx = input_init(NULL, NULL, NULL);
|
||||
data->mx = data->cx;
|
||||
data->my = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
data->showmark = 0;
|
||||
|
||||
3
window.c
3
window.c
@@ -683,7 +683,6 @@ window_pane_update_focus(struct window_pane *wp)
|
||||
c->session->attached != 0 &&
|
||||
(c->flags & CLIENT_FOCUSED) &&
|
||||
c->session->curw->window == wp->window &&
|
||||
c->overlay_draw == NULL &&
|
||||
wp->window->menu == NULL) {
|
||||
focused = 1;
|
||||
break;
|
||||
@@ -1625,7 +1624,7 @@ window_pane_set_event(struct window_pane *wp)
|
||||
NULL, window_pane_error_callback, wp);
|
||||
if (wp->event == NULL)
|
||||
fatalx("out of memory");
|
||||
wp->ictx = input_init(wp, wp->event, &wp->palette, NULL);
|
||||
wp->ictx = input_init(wp, wp->event, &wp->palette);
|
||||
|
||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user