mirror of
https://github.com/tmux/tmux.git
synced 2026-07-22 08:51:17 +00:00
Merge branch 'master' into no_more_overlays
This commit is contained in:
162
CHANGES
162
CHANGES
@@ -1,3 +1,165 @@
|
||||
CHANGES FROM 3.7b TO 3.8
|
||||
|
||||
* Many improvements to floating panes:
|
||||
|
||||
- new-pane and split-window can now set the title with -T and border lines
|
||||
with -B, and new-pane -W waits for the pane command to exit;
|
||||
|
||||
- dragging with Ctrl now creates a new floating pane;
|
||||
|
||||
- modal panes may be created with new-pane -O; a window can have one modal
|
||||
pane and it prevents interaction with the other panes while it is active.
|
||||
A modal pane is now used for the editor in buffer mode;
|
||||
|
||||
- move-pane and resize-pane can now move and resize floating panes, including
|
||||
mouse dragging;
|
||||
|
||||
- split-window in a floating pane creates a new floating pane that does not
|
||||
overlap the active pane, if possible;
|
||||
|
||||
- break-pane can float a tiled pane, join-pane can tile a floating pane, and
|
||||
swap-pane works with floating panes;
|
||||
|
||||
- choose-tree -h and choose-client -h hide the pane containing the mode, and
|
||||
-k for choose commands kills the pane when the mode exits, which is useful
|
||||
for modes in floating panes;
|
||||
|
||||
- pane-border-status has top-floating and bottom-floating, and there are new
|
||||
default bindings under C-b g for common move and resize operations;
|
||||
|
||||
- floating panes are unzoomed before creation to avoid a crash.
|
||||
|
||||
* Add support for themes and improve default colours:
|
||||
|
||||
- tmux now has builtin light and dark colour themes for terminals with 256 or
|
||||
more colours; a new theme option controls whether tmux detects the terminal
|
||||
theme, uses terminal colours, or forces light or dark (set to terminal for
|
||||
the old colours);
|
||||
|
||||
- styles can use new theme colour names such as themeblack, themewhite and
|
||||
themegreen, and colours in styles are expanded as formats;
|
||||
|
||||
- the terminal's own theme is reported to panes instead of being guessed from
|
||||
the background, and inferred more accurately when theme reporting is not
|
||||
supported (Ayman Bagabas, issue 5343);
|
||||
|
||||
- tree-mode-selection-style has been added, tree mode selection styling now
|
||||
covers the whole line, and built-in modes use improved theme colours.
|
||||
|
||||
* Improvements to customize mode:
|
||||
|
||||
- hooks and environment variables are now shown;
|
||||
|
||||
- e opens the selected value in an editor;
|
||||
|
||||
- C toggles showing only changed items;
|
||||
|
||||
- array item keys can now be changed.
|
||||
|
||||
* Hooks (and control mode notifications) are now handled internally by using
|
||||
events, each of which may carry keys and values as a payload. The control
|
||||
mode subscriptions mechanism has been extended to allow general-purpose
|
||||
"monitors" which check a format every second and trigger a hook when it
|
||||
changes or becomes true:
|
||||
|
||||
- set-hook -B adds a monitor hook using the same subscription syntax as
|
||||
refresh-client -B, and show-hooks -B lists them. -T runs the hook only when
|
||||
the format is true;
|
||||
|
||||
- wait-for -E waits for hooks, notifications or user events, and set-hook -E
|
||||
fires an event immediately;
|
||||
|
||||
- hooks have additional keys available. wait-for -v can be used to see the
|
||||
keys sent with a hook event;
|
||||
|
||||
- new hooks to cover areas including client create and destroy, pane
|
||||
activity, pane mode and prompt changes, pane movement and resizing, session
|
||||
group changes and window creation, close and zoom;
|
||||
|
||||
- OSC 133 escape sequences now trigger events: pane-command-started,
|
||||
pane-command-finished and pane-shell-prompt.
|
||||
|
||||
* Add switch-mode, a fast switcher bound by default to Tab for windows and BTab
|
||||
(S-Tab) for sessions.
|
||||
|
||||
* Pane scrollbars now support auto-hide. This replaces the previous modal
|
||||
behaviour where the pane was resized. With auto-hide, the scrollbar appears
|
||||
while scrolling or while hovered and disappears after pane-scrollbars-timeout
|
||||
(Michael Grant).
|
||||
|
||||
* Change command templates so %% is escaped for single quotes while %1 remains
|
||||
unquoted, preventing single quotes in session or target names from
|
||||
terminating quoted command sections (reported by Aliz Hammond).
|
||||
|
||||
* display-panes is now a mode rather than an overlay, and can be run inside
|
||||
another pane. The -b flag has been removed.
|
||||
|
||||
* Add new-window -E, respawn-pane -E and respawn-window -E as more convenient
|
||||
methods to create an empty pane (rather than using '' for the command).
|
||||
|
||||
* Menus now belong to the window, so appear on all clients.
|
||||
|
||||
* Dragging over an existing copy mode selection now adjusts it (Michael Grant).
|
||||
|
||||
* Rectangle selection in copy mode may extend past the end of the current line
|
||||
to match vi's virtualedit=block behaviour (Mark Kelly, issue 5227).
|
||||
|
||||
* With mode-keys set to vi, scrolling in copy mode now keeps the cursor in the
|
||||
same position relative to the text (Arseniy Simonov, issue 5216).
|
||||
|
||||
* Copy mode no longer exits at the bottom while a selection is in progress
|
||||
(issue 5349).
|
||||
|
||||
* Fix scrollbar initial state so scrollbars appear on new windows (issue 5339).
|
||||
|
||||
* Add style attributes for dimming colours (dim=) and for hyperlinks (link= and
|
||||
nolink) (issues 4842 and 4280 from Moritz Angermann).
|
||||
|
||||
* New format modifiers: O: loops over options, V: loops over environments,
|
||||
the I modifier reports client terminal information, t/d gives a time
|
||||
difference in seconds, c/f and c/b emit colours, and the m operator supports
|
||||
multiple terms and fuzzy matching.
|
||||
|
||||
* Add or improve format variables including client_colours,
|
||||
pane_start_command_list, window_manual_width, window_manual_height,
|
||||
pane_last_output_time, pane_modal_flag and window_modal_pane.
|
||||
|
||||
* Add additional pane sort orders, and a z sort order for choose-tree so
|
||||
floating panes can be sorted by z-index.
|
||||
|
||||
* Add -f filters to kill-pane -a, kill-window -a and kill-session -a (issue
|
||||
4782).
|
||||
|
||||
* Allow server ACLs to use groups as well as users (issue 4917).
|
||||
|
||||
* The mouse option now defaults to on.
|
||||
|
||||
* Fix send-keys -K so keys are inserted in the correct place in the input
|
||||
queue, like keys from key bindings (issue 3476).
|
||||
|
||||
* Fix control mode clients hanging on exit if pty data was still queued (Ben
|
||||
Maurer, issue 5356), and avoid sending notifications to clients which are
|
||||
already exiting (Ben Maurer, issue 5357).
|
||||
|
||||
* Fix grouped sessions sometimes being left as unusable command targets while
|
||||
they are being killed (Bryce Miller, issue 5180).
|
||||
|
||||
* Fix choose mode filtering when more than one pane exists (issue 5326), and
|
||||
fix an infinite loop in customize mode when a filter does not match.
|
||||
|
||||
* Fix regsub when the pattern is anchored at the start (issue 5341).
|
||||
|
||||
* Fix redraw issues around synchronized updates, copy mode, tabs, padding,
|
||||
status lines, menus, popups, wide characters and floating panes. This
|
||||
includes fixes for flicker with alternate screen applications and scrollbars
|
||||
(Michael Grant, issue 5351; Noam Stolero, issue 5350; Aung Myo Kyaw, issue
|
||||
5098).
|
||||
|
||||
* Do not crash looking for the next or previous session (issue 5344), or when
|
||||
no client is available.
|
||||
|
||||
* Check time periodically in loops rather than for every item (issue 5367).
|
||||
|
||||
CHANGES FROM 3.7a TO 3.7b
|
||||
|
||||
* Fix so that the end of a synchronized update again triggers a redraw.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-capture-pane.c,v 1.67 2026/07/02 10:34:14 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-capture-pane.c,v 1.68 2026/07/20 11:16:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
|
||||
@@ -134,6 +134,7 @@ cmd_capture_pane_grid(struct window_pane *wp, size_t *len)
|
||||
struct screen *s = &wp->base;
|
||||
struct grid *gd = s->grid;
|
||||
struct grid_line *gl;
|
||||
struct osc133_data *od;
|
||||
char *buf = xstrdup(""), *line;
|
||||
char p[11];
|
||||
u_int yy, xx, total = gd->hsize + gd->sy;
|
||||
@@ -149,9 +150,20 @@ cmd_capture_pane_grid(struct window_pane *wp, size_t *len)
|
||||
snprintf(p, sizeof p, "-");
|
||||
else
|
||||
snprintf(p, sizeof p, "%u", yy - gd->hsize);
|
||||
xasprintf(&line, "\tL %u (%s) flags=%s[%x] %u/%u\n", yy,
|
||||
p, grid_line_flags_string(gl->flags), gl->flags,
|
||||
gl->cellused, gl->cellsize);
|
||||
od = &gl->osc133_data;
|
||||
if (gl->flags & GRID_LINE_OSC133_FLAGS) {
|
||||
xasprintf(&line, "\tL %u (%s) flags=%s[%x] "
|
||||
"%u/%u osc133=%u,%u,%u,%u,%u\n", yy, p,
|
||||
grid_line_flags_string(gl->flags), gl->flags,
|
||||
gl->cellused, gl->cellsize, od->prompt_col,
|
||||
od->cmd_col, od->out_start_col,
|
||||
od->out_end_col, od->exit_status);
|
||||
} else {
|
||||
xasprintf(&line, "\tL %u (%s) flags=%s[%x] "
|
||||
"%u/%u\n", yy, p,
|
||||
grid_line_flags_string(gl->flags), gl->flags,
|
||||
gl->cellused, gl->cellsize);
|
||||
}
|
||||
buf = cmd_capture_pane_append(buf, len, line, strlen(line));
|
||||
free(line);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-find.c,v 1.86 2026/07/02 08:47:25 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-find.c,v 1.87 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -884,7 +884,7 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
|
||||
if (c->session != NULL) {
|
||||
cmd_find_clear_state(fs, flags);
|
||||
|
||||
fs->wp = server_client_get_pane(c);
|
||||
fs->wp = c->session->curw->window->active;
|
||||
if (fs->wp == NULL) {
|
||||
cmd_find_from_session(fs, c->session, flags);
|
||||
return (0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-join-pane.c,v 1.72 2026/07/15 13:02:33 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-join-pane.c,v 1.73 2026/07/17 15:24:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
|
||||
@@ -186,6 +186,7 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
@@ -358,6 +359,7 @@ cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
@@ -397,6 +399,7 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-refresh-client.c,v 1.54 2026/07/05 08:24:00 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-refresh-client.c,v 1.55 2026/07/17 08:37:29 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -66,7 +66,6 @@ cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
const char *size = args_get(args, 'C');
|
||||
u_int w, x, y;
|
||||
struct client_window *cw;
|
||||
|
||||
if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) {
|
||||
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
|
||||
@@ -76,22 +75,16 @@ cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
log_debug("%s: client %s window @%u: size %ux%u", __func__,
|
||||
tc->name, w, x, y);
|
||||
cw = server_client_add_client_window(tc, w);
|
||||
cw->sx = x;
|
||||
cw->sy = y;
|
||||
control_set_window_size(tc, w, x, y);
|
||||
tc->flags |= CLIENT_WINDOWSIZECHANGED;
|
||||
recalculate_sizes_now(1);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (sscanf(size, "@%u:", &w) == 1) {
|
||||
cw = server_client_get_client_window(tc, w);
|
||||
if (cw != NULL) {
|
||||
log_debug("%s: client %s window @%u: no size", __func__,
|
||||
tc->name, w);
|
||||
cw->sx = 0;
|
||||
cw->sy = 0;
|
||||
recalculate_sizes_now(1);
|
||||
}
|
||||
log_debug("%s: client %s window @%u: no size", __func__,
|
||||
tc->name, w);
|
||||
control_clear_window_size(tc, w);
|
||||
recalculate_sizes_now(1);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-run-shell.c,v 1.92 2026/07/14 17:17:17 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-run-shell.c,v 1.93 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -90,8 +90,8 @@ cmd_run_shell_print(struct job *job, const char *msg)
|
||||
cmdq_print(cdata->item, "%s", msg);
|
||||
return;
|
||||
}
|
||||
if (cdata->item != NULL && cdata->client != NULL)
|
||||
wp = server_client_get_pane(cdata->client);
|
||||
if (cdata->client != NULL && cdata->client->session != NULL)
|
||||
wp = cdata->client->session->curw->window->active;
|
||||
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
|
||||
wp = fs.wp;
|
||||
if (wp == NULL)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-select-pane.c,v 1.76 2026/07/10 13:38:45 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-select-pane.c,v 1.77 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -150,13 +150,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
const struct cmd_entry *entry = cmd_get_entry(self);
|
||||
struct cmd_find_state *current = cmdq_get_current(item);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct session *s = target->s;
|
||||
struct window_pane *wp = target->wp, *activewp, *lastwp;
|
||||
struct window_pane *wp = target->wp, *lastwp;
|
||||
struct options *oo = wp->options;
|
||||
char *title;
|
||||
const char *style;
|
||||
@@ -267,18 +266,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
|
||||
activewp = server_client_get_pane(c);
|
||||
else
|
||||
activewp = w->active;
|
||||
if (wp == activewp)
|
||||
if (wp == w->active)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, wp);
|
||||
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
|
||||
server_client_set_pane(c, wp);
|
||||
else if (window_set_active_pane(w, wp, 1))
|
||||
if (window_set_active_pane(w, wp, 1))
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
cmdq_insert_hook(s, item, current, "after-select-pane");
|
||||
cmd_select_pane_redraw(w);
|
||||
|
||||
52
cmd.c
52
cmd.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd.c,v 1.188 2026/07/15 13:02:33 nicm Exp $ */
|
||||
/* $OpenBSD: cmd.c,v 1.189 2026/07/17 08:29:34 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -840,14 +840,19 @@ cmd_mouse_pane(struct mouse_event *m, struct session **sp,
|
||||
return (wp);
|
||||
}
|
||||
|
||||
/* Replace the first %% or %idx in template by s. */
|
||||
/*
|
||||
* Replace the first %% or any %idx in template by s. %% is intended for use in
|
||||
* single quotes, so ' is escaped. %%% and %idx% are for double quotes, so a
|
||||
* list of special characters is escaped. %idx is left unescaped.
|
||||
*/
|
||||
char *
|
||||
cmd_template_replace(const char *template, const char *s, int idx)
|
||||
{
|
||||
char ch, *buf;
|
||||
const char *ptr, *cp, quote[] = "\"\\$;~";
|
||||
int replaced, quoted;
|
||||
size_t len, slen;
|
||||
char ch, *buf;
|
||||
const char *ptr, *cp, dquote[] = "\"\\$;~";
|
||||
int replaced;
|
||||
size_t len, slen;
|
||||
enum { NQ, SQ, DQ } quote;
|
||||
|
||||
if (strchr(template, '%') == NULL)
|
||||
return (xstrdup(template));
|
||||
@@ -861,23 +866,39 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
while (*ptr != '\0') {
|
||||
switch (ch = *ptr++) {
|
||||
case '%':
|
||||
if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
|
||||
if (*ptr >= '1' && *ptr <= '9' && *ptr - '0' == idx) {
|
||||
ptr++;
|
||||
quote = NQ;
|
||||
if (*ptr == '%') {
|
||||
quote = DQ;
|
||||
ptr++;
|
||||
}
|
||||
} else {
|
||||
if (*ptr != '%' || replaced)
|
||||
break;
|
||||
replaced = 1;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
quoted = (*ptr == '%');
|
||||
if (quoted)
|
||||
ptr++;
|
||||
quote = SQ;
|
||||
if (*ptr == '%') {
|
||||
quote = DQ;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
slen = strlen(s);
|
||||
if (slen >= SIZE_MAX / 3 || len > SIZE_MAX - (slen * 3) - 1)
|
||||
if (slen >= SIZE_MAX / 4 ||
|
||||
len > SIZE_MAX - (slen * 4) - 1)
|
||||
fatalx("argument too long");
|
||||
buf = xrealloc(buf, len + (slen * 3) + 1);
|
||||
buf = xrealloc(buf, len + (slen * 4) + 1);
|
||||
for (cp = s; *cp != '\0'; cp++) {
|
||||
if (quoted && strchr(quote, *cp) != NULL)
|
||||
if (quote == SQ && *cp == '\'') {
|
||||
buf[len++] = '\'';
|
||||
buf[len++] = '\\';
|
||||
buf[len++] = '\'';
|
||||
buf[len++] = '\'';
|
||||
continue;
|
||||
}
|
||||
if (quote == DQ && strchr(dquote, *cp) != NULL)
|
||||
buf[len++] = '\\';
|
||||
buf[len++] = *cp;
|
||||
}
|
||||
@@ -891,5 +912,6 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
log_debug("%s: %s -> %s", __func__, template, buf);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
91
control.c
91
control.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: control.c,v 1.61 2026/07/10 15:45:11 nicm Exp $ */
|
||||
/* $OpenBSD: control.c,v 1.62 2026/07/17 08:37:29 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -78,9 +78,20 @@ struct control_pane {
|
||||
};
|
||||
RB_HEAD(control_panes, control_pane);
|
||||
|
||||
/* Control client window size. */
|
||||
struct control_window {
|
||||
u_int window;
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
|
||||
RB_ENTRY(control_window) entry;
|
||||
};
|
||||
RB_HEAD(control_windows, control_window);
|
||||
|
||||
/* Control client state. */
|
||||
struct control_state {
|
||||
struct control_panes panes;
|
||||
struct control_windows windows;
|
||||
|
||||
TAILQ_HEAD(, control_pane) pending_list;
|
||||
u_int pending_count;
|
||||
@@ -120,6 +131,18 @@ control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2)
|
||||
}
|
||||
RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp);
|
||||
|
||||
/* Compare control windows. */
|
||||
static int
|
||||
control_window_cmp(struct control_window *cw1, struct control_window *cw2)
|
||||
{
|
||||
if (cw1->window < cw2->window)
|
||||
return (-1);
|
||||
if (cw1->window > cw2->window)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
RB_GENERATE_STATIC(control_windows, control_window, entry, control_window_cmp);
|
||||
|
||||
/* Free a block. */
|
||||
static void
|
||||
control_free_block(struct control_state *cs, struct control_block *cb)
|
||||
@@ -161,6 +184,66 @@ control_add_pane(struct client *c, struct window_pane *wp)
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/* Get window for this client. */
|
||||
static struct control_window *
|
||||
control_get_window(struct client *c, u_int window)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_window cw = { .window = window };
|
||||
|
||||
if (cs == NULL)
|
||||
return (NULL);
|
||||
return (RB_FIND(control_windows, &cs->windows, &cw));
|
||||
}
|
||||
|
||||
/* Set window size for this client. */
|
||||
void
|
||||
control_set_window_size(struct client *c, u_int window, u_int sx, u_int sy)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_window *cw;
|
||||
|
||||
if (cs == NULL)
|
||||
return;
|
||||
cw = control_get_window(c, window);
|
||||
if (cw == NULL) {
|
||||
cw = xcalloc(1, sizeof *cw);
|
||||
cw->window = window;
|
||||
RB_INSERT(control_windows, &cs->windows, cw);
|
||||
}
|
||||
cw->sx = sx;
|
||||
cw->sy = sy;
|
||||
}
|
||||
|
||||
/* Get window size for this client. */
|
||||
int
|
||||
control_get_window_size(struct client *c, u_int window, u_int *sx, u_int *sy)
|
||||
{
|
||||
struct control_window *cw;
|
||||
|
||||
if ((cw = control_get_window(c, window)) == NULL)
|
||||
return (0);
|
||||
*sx = cw->sx;
|
||||
*sy = cw->sy;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Clear window size for this client. */
|
||||
void
|
||||
control_clear_window_size(struct client *c, u_int window)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_window *cw;
|
||||
|
||||
if (cs == NULL)
|
||||
return;
|
||||
cw = control_get_window(c, window);
|
||||
if (cw != NULL) {
|
||||
RB_REMOVE(control_windows, &cs->windows, cw);
|
||||
free(cw);
|
||||
}
|
||||
}
|
||||
|
||||
/* Discard output for a pane. */
|
||||
static void
|
||||
control_discard_pane(struct client *c, struct control_pane *cp)
|
||||
@@ -749,6 +832,7 @@ control_start(struct client *c)
|
||||
|
||||
cs = c->control_state = xcalloc(1, sizeof *cs);
|
||||
RB_INIT(&cs->panes);
|
||||
RB_INIT(&cs->windows);
|
||||
TAILQ_INIT(&cs->pending_list);
|
||||
TAILQ_INIT(&cs->all_blocks);
|
||||
cs->subs = monitor_create_client(c, control_sub_change, NULL);
|
||||
@@ -800,6 +884,7 @@ control_stop(struct client *c)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_block *cb, *cb1;
|
||||
struct control_window *cw, *cw1;
|
||||
|
||||
if (cs == NULL)
|
||||
return;
|
||||
@@ -811,6 +896,10 @@ control_stop(struct client *c)
|
||||
bufferevent_free(cs->read_event);
|
||||
|
||||
control_reset_offsets(c);
|
||||
RB_FOREACH_SAFE(cw, control_windows, &cs->windows, cw1) {
|
||||
RB_REMOVE(control_windows, &cs->windows, cw);
|
||||
free(cw);
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
|
||||
control_free_block(cs, cb);
|
||||
|
||||
|
||||
81
format.c
81
format.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: format.c,v 1.405 2026/07/15 13:02:33 nicm Exp $ */
|
||||
/* $OpenBSD: format.c,v 1.407 2026/07/20 07:42:13 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -2578,6 +2578,79 @@ format_cb_pane_tty(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_unzoomed_height. */
|
||||
static void *
|
||||
format_cb_pane_unzoomed_height(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
struct window *w;
|
||||
struct layout_cell *lc, *root;
|
||||
int status, floating;
|
||||
u_int sy;
|
||||
|
||||
if (wp == NULL)
|
||||
return (NULL);
|
||||
w = wp->window;
|
||||
|
||||
lc = wp->saved_layout_cell;
|
||||
if (lc == NULL)
|
||||
lc = wp->layout_cell;
|
||||
if (lc == NULL)
|
||||
return (NULL);
|
||||
sy = lc->g.sy;
|
||||
floating = (lc->flags & LAYOUT_CELL_FLOATING);
|
||||
|
||||
root = w->saved_layout_root;
|
||||
if (root == NULL)
|
||||
root = w->layout_root;
|
||||
if (lc == wp->saved_layout_cell && !floating)
|
||||
status = window_get_pane_status(w);
|
||||
else
|
||||
status = window_pane_get_pane_status(wp);
|
||||
if (!floating &&
|
||||
root != NULL &&
|
||||
layout_add_horizontal_border(root, lc, status) &&
|
||||
sy > 1)
|
||||
sy--;
|
||||
|
||||
return (format_printf("%u", sy));
|
||||
}
|
||||
|
||||
/* Callback for pane_unzoomed_width. */
|
||||
static void *
|
||||
format_cb_pane_unzoomed_width(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
struct layout_cell *lc;
|
||||
int sb_w, sb_pad;
|
||||
u_int sx;
|
||||
|
||||
if (wp == NULL)
|
||||
return (NULL);
|
||||
|
||||
lc = wp->saved_layout_cell;
|
||||
if (lc == NULL)
|
||||
lc = wp->layout_cell;
|
||||
if (lc == NULL)
|
||||
return (NULL);
|
||||
sx = lc->g.sx;
|
||||
|
||||
if (window_pane_scrollbar_reserve(wp)) {
|
||||
sb_w = wp->scrollbar_style.width;
|
||||
sb_pad = wp->scrollbar_style.pad;
|
||||
if (sb_w < 1)
|
||||
sb_w = 1;
|
||||
if (sb_pad < 0)
|
||||
sb_pad = 0;
|
||||
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM)
|
||||
sx = PANE_MINIMUM;
|
||||
else
|
||||
sx -= sb_w + sb_pad;
|
||||
}
|
||||
|
||||
return (format_printf("%u", sx));
|
||||
}
|
||||
|
||||
/* Callback for pane_width. */
|
||||
static void *
|
||||
format_cb_pane_width(struct format_tree *ft)
|
||||
@@ -3764,6 +3837,12 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_unseen_changes", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_unseen_changes
|
||||
},
|
||||
{ "pane_unzoomed_height", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_unzoomed_height
|
||||
},
|
||||
{ "pane_unzoomed_width", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_unzoomed_width
|
||||
},
|
||||
{ "pane_width", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_width
|
||||
},
|
||||
|
||||
31
grid.c
31
grid.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: grid.c,v 1.153 2026/07/02 08:51:05 nicm Exp $ */
|
||||
/* $OpenBSD: grid.c,v 1.154 2026/07/20 11:16:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -233,6 +233,25 @@ grid_get_line(struct grid *gd, u_int line)
|
||||
return (&gd->linedata[line]);
|
||||
}
|
||||
|
||||
/* Get line time. */
|
||||
time_t
|
||||
grid_line_time(const struct grid_line *gl)
|
||||
{
|
||||
if (gl->time == 0)
|
||||
return (0);
|
||||
return (start_time.tv_sec + gl->time - 1);
|
||||
}
|
||||
|
||||
/* Set line time. */
|
||||
static void
|
||||
grid_line_set_time(struct grid_line *gl)
|
||||
{
|
||||
if (current_time == 0)
|
||||
gl->time = 0;
|
||||
else
|
||||
gl->time = current_time - start_time.tv_sec + 1;
|
||||
}
|
||||
|
||||
/* Adjust number of lines. */
|
||||
void
|
||||
grid_adjust_lines(struct grid *gd, u_int lines)
|
||||
@@ -486,7 +505,7 @@ grid_scroll_history(struct grid *gd, u_int bg)
|
||||
|
||||
gd->hscrolled++;
|
||||
grid_compact_line(&gd->linedata[gd->hsize]);
|
||||
gd->linedata[gd->hsize].time = current_time;
|
||||
grid_line_set_time(&gd->linedata[gd->hsize]);
|
||||
gd->hsize++;
|
||||
gd->scroll_added++;
|
||||
}
|
||||
@@ -528,7 +547,7 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
|
||||
|
||||
/* Move the line into the history. */
|
||||
memcpy(gl_history, gl_upper, sizeof *gl_history);
|
||||
gl_history->time = current_time;
|
||||
grid_line_set_time(gl_history);
|
||||
|
||||
/* Then move the region up and clear the bottom line. */
|
||||
memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper);
|
||||
@@ -1701,8 +1720,14 @@ grid_line_flags_string(int flags)
|
||||
strlcat(s, "DEAD,", sizeof s);
|
||||
if (flags & GRID_LINE_START_PROMPT)
|
||||
strlcat(s, "START_PROMPT,", sizeof s);
|
||||
if (flags & GRID_LINE_SECOND_PROMPT)
|
||||
strlcat(s, "SECOND_PROMPT,", sizeof s);
|
||||
if (flags & GRID_LINE_START_COMMAND)
|
||||
strlcat(s, "START_COMMAND,", sizeof s);
|
||||
if (flags & GRID_LINE_START_OUTPUT)
|
||||
strlcat(s, "START_OUTPUT,", sizeof s);
|
||||
if (flags & GRID_LINE_END_OUTPUT)
|
||||
strlcat(s, "END_OUTPUT,", sizeof s);
|
||||
if (flags & GRID_LINE_HYPERLINK)
|
||||
strlcat(s, "HYPERLINK,", sizeof s);
|
||||
if (*s == '\0')
|
||||
|
||||
113
input.c
113
input.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: input.c,v 1.268 2026/07/13 15:03:03 nicm Exp $ */
|
||||
/* $OpenBSD: input.c,v 1.269 2026/07/20 11:16:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -173,8 +173,6 @@ static void input_osc_110(struct input_ctx *, const char *);
|
||||
static void input_osc_111(struct input_ctx *, const char *);
|
||||
static void input_osc_112(struct input_ctx *, const char *);
|
||||
static void input_osc_133(struct input_ctx *, const char *);
|
||||
static void input_fire_pane_title_changed(struct window_pane *,
|
||||
const char *);
|
||||
|
||||
/* Transition entry/exit handlers. */
|
||||
static void input_clear(struct input_ctx *);
|
||||
@@ -211,21 +209,6 @@ static int input_end_bel(struct input_ctx *);
|
||||
/* Command table comparison function. */
|
||||
static int input_table_compare(const void *, const void *);
|
||||
|
||||
static void
|
||||
input_fire_pane_title_changed(struct window_pane *wp, const char *title)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
}
|
||||
|
||||
/* Command table entry. */
|
||||
struct input_table_entry {
|
||||
int ch;
|
||||
@@ -808,6 +791,22 @@ input_stop_utf8(struct input_ctx *ictx)
|
||||
ictx->utf8started = 0;
|
||||
}
|
||||
|
||||
/* Fire a title changed event. */
|
||||
static void
|
||||
input_fire_pane_title_changed(struct window_pane *wp, const char *title)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer - if this expires then have been waiting for a terminator for too
|
||||
* long, so reset to ground.
|
||||
@@ -3190,6 +3189,35 @@ input_osc_112(struct input_ctx *ictx, const char *p)
|
||||
screen_set_cursor_colour(ictx->ctx.s, -1);
|
||||
}
|
||||
|
||||
/* Parse the OSC 133 D exit status. */
|
||||
static int
|
||||
input_osc_133_exit_status(const char *p)
|
||||
{
|
||||
const char *end;
|
||||
char *copy;
|
||||
const char *errstr;
|
||||
long long status;
|
||||
|
||||
if (p[1] != ';' || p[2] == '\0' || strchr(p + 2, '=') == p + 2)
|
||||
return (0);
|
||||
end = strchr(p + 2, ';');
|
||||
if (end == p + 2)
|
||||
return (0);
|
||||
if (end == NULL)
|
||||
copy = xstrdup(p + 2);
|
||||
else
|
||||
copy = xstrndup(p + 2, end - (p + 2));
|
||||
if (strchr(copy, '=') != NULL) {
|
||||
free(copy);
|
||||
return (0);
|
||||
}
|
||||
status = strtonum(copy, 0, 255, &errstr);
|
||||
free(copy);
|
||||
if (errstr != NULL)
|
||||
return (255);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* Fire an OSC 133 command event. */
|
||||
static void
|
||||
input_fire_command_event(struct window_pane *wp, const char *name)
|
||||
@@ -3235,27 +3263,51 @@ static void
|
||||
input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct grid *gd = ictx->ctx.s->grid;
|
||||
u_int line = ictx->ctx.s->cy + gd->hsize;
|
||||
struct screen *s = ictx->ctx.s;
|
||||
struct grid *gd = s->grid;
|
||||
u_int line = s->cy + gd->hsize;
|
||||
struct grid_line *gl = NULL;
|
||||
const char *errstr;
|
||||
const char *cp;
|
||||
int status;
|
||||
|
||||
if (line <= gd->hsize + gd->sy - 1)
|
||||
if (line < gd->hsize + gd->sy)
|
||||
gl = grid_get_line(gd, line);
|
||||
|
||||
switch (*p) {
|
||||
case 'A':
|
||||
if (gl != NULL)
|
||||
case 'N':
|
||||
if (gl != NULL) {
|
||||
memset(&gl->osc133_data, 0, sizeof gl->osc133_data);
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
}
|
||||
if (wp != NULL) {
|
||||
wp->last_prompt_time = time(NULL);
|
||||
events_fire_pane("pane-shell-prompt", wp);
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
if (gl != NULL) {
|
||||
cp = strstr(p, ";k=s");
|
||||
if (cp != NULL && (cp[4] == ';' || cp[4] == '\0'))
|
||||
gl->flags |= GRID_LINE_SECOND_PROMPT;
|
||||
else
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
case 'I':
|
||||
if (gl != NULL) {
|
||||
gl->flags |= GRID_LINE_START_COMMAND;
|
||||
gl->osc133_data.cmd_col = s->cx;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (gl != NULL)
|
||||
if (gl != NULL) {
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
gl->osc133_data.out_start_col = s->cx;
|
||||
}
|
||||
if (wp != NULL) {
|
||||
wp->cmd_start_time = time(NULL);
|
||||
wp->cmd_end_time = 0;
|
||||
@@ -3265,17 +3317,18 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
status = input_osc_133_exit_status(p);
|
||||
if (wp != NULL) {
|
||||
wp->cmd_end_time = time(NULL);
|
||||
wp->flags &= ~PANE_CMDRUNNING;
|
||||
wp->cmd_status = -1;
|
||||
if (p[1] == ';' && p[2] != '\0') {
|
||||
status = strtonum(p + 2, 0, INT_MAX, &errstr);
|
||||
if (errstr == NULL)
|
||||
wp->cmd_status = status;
|
||||
}
|
||||
wp->cmd_status = status;
|
||||
input_fire_command_event(wp, "pane-command-finished");
|
||||
}
|
||||
if (gl != NULL) {
|
||||
gl->flags |= GRID_LINE_END_OUTPUT;
|
||||
gl->osc133_data.out_end_col = s->cx;
|
||||
gl->osc133_data.exit_status = status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: options-table.c,v 1.238 2026/07/15 13:02:33 nicm Exp $ */
|
||||
/* $OpenBSD: options-table.c,v 1.239 2026/07/19 17:36:38 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1348,7 +1348,8 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "display-panes-format",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "#[align=right]#{pane_width}x#{pane_height}",
|
||||
.default_str = "#[align=right]"
|
||||
"#{pane_unzoomed_width}x#{pane_unzoomed_height}",
|
||||
.text = "Format of text shown by 'display-panes', expanded for each "
|
||||
"pane."
|
||||
},
|
||||
|
||||
41
regress/cfg-client-lost.sh
Executable file
41
regress/cfg-client-lost.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
TMPDIR=$(mktemp -d) || exit 1
|
||||
TMUX="$TEST_TMUX -S$TMPDIR/tmux.sock"
|
||||
CONF="$TMPDIR/tmux.conf"
|
||||
READY="$TMPDIR/ready"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
rm -rf "$TMPDIR"
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
cat <<EOF >$CONF
|
||||
new-session -d -s keep 'sleep 1000'
|
||||
run-shell -b 'touch $READY'
|
||||
run-shell -d 1 true
|
||||
source-file /dev/null
|
||||
EOF
|
||||
|
||||
$TMUX -f$CONF new-session -d -s client 'sleep 100' &
|
||||
pid=$!
|
||||
i=0
|
||||
while [ ! -f "$READY" ]; do
|
||||
[ "$i" -eq 50 ] && exit 1
|
||||
i=$((i + 1))
|
||||
sleep 0.1
|
||||
done
|
||||
kill "$pid" 2>/dev/null
|
||||
wait "$pid" 2>/dev/null
|
||||
|
||||
sleep 2
|
||||
$TMUX has-session -t keep || exit 1
|
||||
|
||||
exit 0
|
||||
181
regress/cmd-template-replace.sh
Normal file
181
regress/cmd-template-replace.sh
Normal file
@@ -0,0 +1,181 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Exercise cmd_template_replace through command-prompt, which passes prompt
|
||||
# input as argv to args_make_commands. This covers the quoting modes, indexed
|
||||
# replacements, and cases where replacements are intentionally not made.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMP=$(mktemp -d) || exit 1
|
||||
TMUX_TMPDIR="$TMP"
|
||||
export TMUX_TMPDIR
|
||||
|
||||
OUT="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
IN="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$OUT kill-server 2>/dev/null
|
||||
$IN kill-server 2>/dev/null
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "[FAIL] $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
settle()
|
||||
{
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
wait_option()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ "$i" -lt 30 ]; do
|
||||
value=$($IN show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
accept_prompt()
|
||||
{
|
||||
key=$1
|
||||
value=$2
|
||||
|
||||
$OUT send-keys "$key" || exit 1
|
||||
settle
|
||||
$OUT send-keys -l "$value" || exit 1
|
||||
$OUT send-keys Enter || exit 1
|
||||
settle
|
||||
}
|
||||
|
||||
accept_two_prompts()
|
||||
{
|
||||
key=$1
|
||||
first=$2
|
||||
second=$3
|
||||
|
||||
$OUT send-keys "$key" || exit 1
|
||||
settle
|
||||
$OUT send-keys -l "$first" || exit 1
|
||||
$OUT send-keys Enter || exit 1
|
||||
settle
|
||||
$OUT send-keys -l "$second" || exit 1
|
||||
$OUT send-keys Enter || exit 1
|
||||
settle
|
||||
}
|
||||
|
||||
reset_options()
|
||||
{
|
||||
for option in \
|
||||
@r @first @second @plain @raw_tail @one @two @two_again \
|
||||
@double_index @marker; do
|
||||
$IN set -g "$option" SENTINEL || exit 1
|
||||
done
|
||||
$IN set -g @marker unchanged || exit 1
|
||||
}
|
||||
|
||||
$IN new -d -x80 -y24 "sh -c 'exec sleep 1000'" || exit 1
|
||||
$IN set -g status on || exit 1
|
||||
$IN set -g status-keys emacs || exit 1
|
||||
$IN set -g window-size manual || exit 1
|
||||
|
||||
$IN bind -n M-s command-prompt -p '(single)' "set -g @r '%%'" ||
|
||||
exit 1
|
||||
$IN bind -n M-f command-prompt -p '(first)' \
|
||||
"set -g @first '%%' ; set -g @second '%%'" ||
|
||||
exit 1
|
||||
$IN bind -n M-d command-prompt -p '(double)' 'set -g @r "%%%"' ||
|
||||
exit 1
|
||||
$IN bind -n M-r command-prompt -p '(raw)' "set -g @r %1" ||
|
||||
exit 1
|
||||
$IN bind -n M-a command-prompt -p '(all)' \
|
||||
"set -g @first %1 ; set -g @second %1" ||
|
||||
exit 1
|
||||
$IN bind -n M-m command-prompt -p 'one,two' \
|
||||
"set -g @one %1 ; set -g @two %2 ; set -g @two_again %2" ||
|
||||
exit 1
|
||||
$IN bind -n M-i command-prompt -p 'one,two' 'set -g @double_index "%2%"' ||
|
||||
exit 1
|
||||
$IN bind -n M-n command-prompt -p '(none)' \
|
||||
"set -g @plain no-template-markers" ||
|
||||
exit 1
|
||||
|
||||
$OUT new -d -x80 -y24 || exit 1
|
||||
$OUT set -g status off || exit 1
|
||||
$OUT set -g window-size manual || exit 1
|
||||
$OUT send-keys -l "$IN attach" || exit 1
|
||||
$OUT send-keys Enter || exit 1
|
||||
sleep 1
|
||||
|
||||
reset_options
|
||||
|
||||
# %% is for templates already inside single quotes. A single quote in the
|
||||
# replacement must stay data and must not close the surrounding quotes.
|
||||
payload="can't ; set -g @marker changed ; done"
|
||||
accept_prompt M-s "$payload"
|
||||
wait_option @r "$payload"
|
||||
wait_option @marker unchanged
|
||||
|
||||
# Only the first %% is replaced.
|
||||
reset_options
|
||||
payload="first'value"
|
||||
accept_prompt M-f "$payload"
|
||||
wait_option @first "$payload"
|
||||
wait_option @second %%
|
||||
|
||||
# %%% keeps the previous double-quote escaping behaviour.
|
||||
reset_options
|
||||
payload='a"$;~\z'
|
||||
accept_prompt M-d "$payload"
|
||||
wait_option @r "$payload"
|
||||
|
||||
# %1 is intentionally left raw as an escape hatch.
|
||||
reset_options
|
||||
$IN set -g @raw_tail unchanged || exit 1
|
||||
accept_prompt M-r 'raw ; set -g @raw_tail yes'
|
||||
wait_option @r raw
|
||||
wait_option @raw_tail yes
|
||||
|
||||
# All instances of %1 are replaced.
|
||||
reset_options
|
||||
accept_prompt M-a repeat
|
||||
wait_option @first repeat
|
||||
wait_option @second repeat
|
||||
|
||||
# %1 and %2 select different prompt values, and all instances of %2 are
|
||||
# replaced.
|
||||
reset_options
|
||||
accept_two_prompts M-m one two
|
||||
wait_option @one one
|
||||
wait_option @two two
|
||||
wait_option @two_again two
|
||||
|
||||
# %idx% uses double-quote escaping for indexed replacements.
|
||||
reset_options
|
||||
payload='b"$;~\y'
|
||||
accept_two_prompts M-i ignored "$payload"
|
||||
wait_option @double_index "$payload"
|
||||
|
||||
# A template without replacement markers is left alone.
|
||||
reset_options
|
||||
accept_prompt M-n 'unused ; set -g @marker changed'
|
||||
wait_option @plain no-template-markers
|
||||
wait_option @marker unchanged
|
||||
|
||||
exit 0
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
# 947
|
||||
# size in control mode should change after refresh-client -C, and -x and -y
|
||||
# should work without -d for control clients
|
||||
# size in control mode should change after refresh-client -C, per-window
|
||||
# control client sizes should work, and -x and -y should work without -d for
|
||||
# control clients
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
@@ -47,4 +48,21 @@ $TMUX ls -F':#{window_width} #{window_height}' >>$OUT
|
||||
printf ":100 50\n:80 24\n"|cmp -s $OUT - || exit 1
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMUX="$TEST_TMUX -LtestA$$-4 -f/dev/null"
|
||||
$TMUX -f/dev/null new -d || exit 1
|
||||
$TMUX neww || exit 1
|
||||
w0=$($TMUX display -p -t :0 '#{window_id}')
|
||||
w1=$($TMUX display -p -t :1 '#{window_id}')
|
||||
cat <<EOF|$TMUX -f/dev/null -C a >$TMP
|
||||
refresh -C 80,24
|
||||
refresh -C ${w0}:40x10
|
||||
display -p -t ${w0} 'w0 #{window_width} #{window_height}'
|
||||
display -p -t ${w1} 'w1 #{window_width} #{window_height}'
|
||||
refresh -C ${w0}:
|
||||
display -p -t ${w0} 'w0c #{window_width} #{window_height}'
|
||||
EOF
|
||||
grep ^w $TMP >$OUT
|
||||
printf "w0 40 10\nw1 80 24\nw0c 80 24\n"|cmp -s $OUT - || exit 1
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -73,11 +73,14 @@ $TMUX new-session -d -s m -x 80 -y 24 'cat' || exit 1
|
||||
$TMUX split-window -t m:0 'cat' || exit 1
|
||||
p0=$($TMUX display-message -p -t m:0.0 '#{pane_id}')
|
||||
p1=$($TMUX display-message -p -t m:0.1 '#{pane_id}')
|
||||
$TMUX set -g display-panes-format 'P#{pane_index}' ||
|
||||
$TMUX set -g display-panes-format \
|
||||
'P#{pane_index}:#{pane_unzoomed_width}x#{pane_unzoomed_height}' ||
|
||||
fail "set display-panes-format failed"
|
||||
|
||||
$TMUX2 new-session -d -s out -x 80 -y 24 "$TMUX attach -t m" || exit 1
|
||||
wait_clients 1
|
||||
p0_size=$($TMUX display-message -p -t "$p0" '#{pane_width}x#{pane_height}')
|
||||
p1_size=$($TMUX display-message -p -t "$p1" '#{pane_width}x#{pane_height}')
|
||||
|
||||
capture()
|
||||
{
|
||||
@@ -100,11 +103,38 @@ wait_capture()
|
||||
$TMUX display-panes -d 0 -t "$p0" || fail "display-panes failed"
|
||||
wait_format "$p0" '#{pane_mode}' 'panes-mode'
|
||||
wait_format "$p0" '#{window_zoomed_flag}' '1'
|
||||
wait_capture 'P0'
|
||||
wait_capture 'P1'
|
||||
wait_format "$p0" '#{pane_unzoomed_width}x#{pane_unzoomed_height}' \
|
||||
"$p0_size"
|
||||
wait_capture "P0:$p0_size"
|
||||
wait_capture "P1:$p1_size"
|
||||
$TMUX send-keys -t "$p0" q || fail "exit panes mode failed"
|
||||
wait_format "$p0" '#{pane_in_mode}' '0'
|
||||
wait_format "$p0" '#{window_zoomed_flag}' '0'
|
||||
$TMUX set -g display-panes-format 'P#{pane_index}' ||
|
||||
fail "reset display-panes-format failed"
|
||||
|
||||
# Unzoomed sizes match the visible pane size when scrollbars reserve space.
|
||||
$TMUX set -w -t m:0 pane-scrollbars on ||
|
||||
fail "set pane-scrollbars failed"
|
||||
$TMUX set -w -t m:0 pane-scrollbars-style "width=2,pad=1" ||
|
||||
fail "set pane-scrollbars-style failed"
|
||||
p0_size=$($TMUX display-message -p -t "$p0" '#{pane_width}x#{pane_height}')
|
||||
p1_size=$($TMUX display-message -p -t "$p1" '#{pane_width}x#{pane_height}')
|
||||
$TMUX set -g display-panes-format \
|
||||
'S#{pane_index}:#{pane_unzoomed_width}x#{pane_unzoomed_height}' ||
|
||||
fail "set scrollbar display-panes-format failed"
|
||||
$TMUX display-panes -d 0 -t "$p0" || fail "display-panes scrollbar failed"
|
||||
wait_format "$p0" '#{window_zoomed_flag}' '1'
|
||||
wait_format "$p0" '#{pane_unzoomed_width}x#{pane_unzoomed_height}' \
|
||||
"$p0_size"
|
||||
wait_capture "S0:$p0_size"
|
||||
wait_capture "S1:$p1_size"
|
||||
$TMUX send-keys -t "$p0" q || fail "exit scrollbar panes mode failed"
|
||||
wait_format "$p0" '#{pane_in_mode}' '0'
|
||||
$TMUX set -w -t m:0 pane-scrollbars off ||
|
||||
fail "reset pane-scrollbars failed"
|
||||
$TMUX set -g display-panes-format 'P#{pane_index}' ||
|
||||
fail "reset display-panes-format after scrollbars failed"
|
||||
|
||||
# -Z starts unzoomed.
|
||||
$TMUX display-panes -Zd 0 -t "$p0" || fail "display-panes -Z failed"
|
||||
@@ -192,13 +222,21 @@ $TMUX set -g display-panes-format 'P#{pane_index}' ||
|
||||
# pane content into the status row.
|
||||
$TMUX set -w -t m:0 pane-border-status top ||
|
||||
fail "set pane-border-status failed"
|
||||
$TMUX set -g display-panes-format '' || fail "clear display-panes-format failed"
|
||||
status_p0_size=$($TMUX display-message -p -t "$p0" \
|
||||
'#{pane_width}x#{pane_height}')
|
||||
status_p1_size=$($TMUX display-message -p -t "$p1" \
|
||||
'#{pane_width}x#{pane_height}')
|
||||
$TMUX set -g display-panes-format \
|
||||
'#[align=right]T#{pane_index}:#{pane_unzoomed_width}x#{pane_unzoomed_height}' ||
|
||||
fail "set status display-panes-format failed"
|
||||
$TMUX respawn-pane -k -t "$p0" 'printf "STATUS-TOP\n"; exec cat' ||
|
||||
fail "write status marker failed"
|
||||
wait_capture 'STATUS-TOP'
|
||||
$TMUX display-panes -d 0 -t "$p0" || fail "display-panes status failed"
|
||||
wait_format "$p0" '#{pane_mode}' 'panes-mode'
|
||||
wait_capture 'STATUS-TOP'
|
||||
wait_capture "T0:$status_p0_size"
|
||||
wait_capture "T1:$status_p1_size"
|
||||
CAPTURED=$(capture)
|
||||
first=$(printf '%s\n' "$CAPTURED" | sed -n '1p')
|
||||
second=$(printf '%s\n' "$CAPTURED" | sed -n '2p')
|
||||
@@ -230,13 +268,18 @@ wait_format "$fp" '#{pane_mode}' 'panes-mode'
|
||||
wait_format "$fp" '#{window_zoomed_flag}' '1'
|
||||
wait_capture '┌'
|
||||
wait_capture '┘'
|
||||
fp_size=$($TMUX display-message -p -t "$fp" \
|
||||
'#{pane_unzoomed_width}x#{pane_unzoomed_height}')
|
||||
[ "$fp_size" = "30x8" ] ||
|
||||
fail "expected floating unzoomed size 30x8, got $fp_size"
|
||||
$TMUX send-keys -t "$fp" q || fail "exit zoomed floating panes mode failed"
|
||||
wait_format "$fp" '#{pane_in_mode}' '0'
|
||||
wait_format "$fp" '#{window_zoomed_flag}' '0'
|
||||
|
||||
$TMUX resize-pane -t "$fp" -x 48 -y 14 ||
|
||||
fail "resize floating pane larger failed"
|
||||
$TMUX set -g display-panes-format '#[align=right]FP#{pane_width}x#{pane_height}' ||
|
||||
$TMUX set -g display-panes-format \
|
||||
'#[align=right]FP#{pane_unzoomed_width}x#{pane_unzoomed_height}' ||
|
||||
fail "set floating display-panes-format failed"
|
||||
$TMUX display-panes -Zd 0 -t "$fp" || fail "display-panes floating format failed"
|
||||
wait_format "$fp" '#{pane_mode}' 'panes-mode'
|
||||
|
||||
@@ -5,11 +5,20 @@
|
||||
start_pane alternate 10 3 'MAIN\033[?1049hALT\033[?1049lZ\n'
|
||||
check_capture alternate 'MAINZ'
|
||||
|
||||
start_pane osc133 10 4 '\033]133;A\007prompt\n\033]133;C\007output\n'
|
||||
check_capture osc133 'prompt
|
||||
output'
|
||||
check_flags osc133 'P prompt
|
||||
O output'
|
||||
start_pane osc133 20 8 'xx\033]133;A\007p>\033]133;B\007cmd\nxy\033]133;P;k=s\007more\nzz\033]133;C\007out\033]133;D;7\007\nq\033]133;C\007bad\033]133;D;-1\007\nqq\033]133;C\007big\033]133;D;300\007\nzzz\033]133;C\007ok\033]133;D\007\n'
|
||||
check_capture osc133 'xxp>cmd
|
||||
xymore
|
||||
zzout
|
||||
qbad
|
||||
qqbig
|
||||
zzzok'
|
||||
check_raw_matches osc133 \
|
||||
'L 0 \(0\) flags=START_PROMPT,START_COMMAND\[[0-9a-f]+\].* osc133=2,4,0,0,0' \
|
||||
'L 1 \(1\) flags=SECOND_PROMPT\[[0-9a-f]+\].* osc133=2,0,0,0,0' \
|
||||
'L 2 \(2\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,2,5,7' \
|
||||
'L 3 \(3\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,1,4,255' \
|
||||
'L 4 \(4\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,2,5,255' \
|
||||
'L 5 \(5\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,3,5,0'
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit $exit_status
|
||||
|
||||
@@ -21,7 +21,7 @@ exit_status=0
|
||||
format_string () {
|
||||
case $1 in
|
||||
*\')
|
||||
printf '"%%%%"'
|
||||
printf '"%%%%%%"'
|
||||
;;
|
||||
*)
|
||||
printf "'%%%%'"
|
||||
|
||||
36
resize.c
36
resize.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: resize.c,v 1.57 2026/07/13 13:01:14 nicm Exp $ */
|
||||
/* $OpenBSD: resize.c,v 1.58 2026/07/17 08:37:29 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -134,9 +134,8 @@ clients_calculate_size(int type, int current, struct client *c,
|
||||
int, int, struct session *, struct window *), u_int *sx, u_int *sy,
|
||||
u_int *xpixel, u_int *ypixel)
|
||||
{
|
||||
struct client *loop;
|
||||
struct client_window *cw;
|
||||
u_int cx, cy, n = 0;
|
||||
struct client *loop;
|
||||
u_int cx, cy, n = 0;
|
||||
|
||||
/*
|
||||
* Start comparing with 0 for largest and UINT_MAX for smallest or
|
||||
@@ -187,20 +186,10 @@ clients_calculate_size(int type, int current, struct client *c,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the client has a per-window size, use this instead if it is
|
||||
* smaller.
|
||||
*/
|
||||
if (w != NULL)
|
||||
cw = server_client_get_client_window(loop, w->id);
|
||||
else
|
||||
cw = NULL;
|
||||
|
||||
/* Work out this client's size. */
|
||||
if (cw != NULL && cw->sx != 0 && cw->sy != 0) {
|
||||
cx = cw->sx;
|
||||
cy = cw->sy;
|
||||
} else {
|
||||
if (w == NULL ||
|
||||
!control_get_window_size(loop, w->id, &cx, &cy) ||
|
||||
cx == 0 || cy == 0) {
|
||||
cx = loop->tty.sx;
|
||||
cy = loop->tty.sy - status_line_size(loop);
|
||||
}
|
||||
@@ -247,17 +236,16 @@ skip:
|
||||
/* Look up per-window size if any. */
|
||||
if (~loop->flags & CLIENT_WINDOWSIZECHANGED)
|
||||
continue;
|
||||
cw = server_client_get_client_window(loop, w->id);
|
||||
if (cw == NULL)
|
||||
if (!control_get_window_size(loop, w->id, &cx, &cy))
|
||||
continue;
|
||||
|
||||
/* Clamp the size. */
|
||||
log_debug("%s: %s size for @%u is %ux%u", __func__,
|
||||
loop->name, w->id, cw->sx, cw->sy);
|
||||
if (cw->sx != 0 && *sx > cw->sx)
|
||||
*sx = cw->sx;
|
||||
if (cw->sy != 0 && *sy > cw->sy)
|
||||
*sy = cw->sy;
|
||||
loop->name, w->id, cx, cy);
|
||||
if (cx != 0 && *sx > cx)
|
||||
*sx = cx;
|
||||
if (cy != 0 && *sy > cy)
|
||||
*sy = cy;
|
||||
}
|
||||
}
|
||||
if (*sx != UINT_MAX && *sy != UINT_MAX)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: screen-redraw.c,v 1.152 2026/07/16 10:52:32 nicm Exp $ */
|
||||
/* $OpenBSD: screen-redraw.c,v 1.153 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1582,7 +1582,7 @@ redraw_set_draw_context(struct redraw_draw_ctx *dctx,
|
||||
|
||||
if (server_is_marked(s, s->curw, marked_pane.wp))
|
||||
dctx->marked = marked_pane.wp;
|
||||
dctx->active = server_client_get_pane(c);
|
||||
dctx->active = s->curw->window->active;
|
||||
|
||||
lines = status_line_size(c);
|
||||
if (options_get_number(oo, "status-position") == 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: screen-write.c,v 1.283 2026/07/09 07:35:05 nicm Exp $ */
|
||||
/* $OpenBSD: screen-write.c,v 1.284 2026/07/20 11:16:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1601,6 +1601,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
|
||||
struct grid_line *gl;
|
||||
u_int sx = screen_size_x(s);
|
||||
struct screen_write_citem *ci = ctx->item;
|
||||
struct osc133_data od;
|
||||
u_int flags;
|
||||
|
||||
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
||||
@@ -1612,10 +1613,12 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
flags = gl->flags & (GRID_LINE_START_PROMPT|GRID_LINE_START_OUTPUT);
|
||||
flags = gl->flags & GRID_LINE_OSC133_FLAGS;
|
||||
memcpy(&od, &gl->osc133_data, sizeof od);
|
||||
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
|
||||
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
||||
gl->flags |= flags;
|
||||
memcpy(&gl->osc133_data, &od, sizeof gl->osc133_data);
|
||||
|
||||
screen_write_collect_clear(ctx, s->cy, 1);
|
||||
ci->x = 0;
|
||||
|
||||
105
server-client.c
105
server-client.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: server-client.c,v 1.494 2026/07/15 14:14:50 nicm Exp $ */
|
||||
/* $OpenBSD: server-client.c,v 1.497 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -50,19 +50,6 @@ static int server_client_dispatch_identify(struct client *, struct imsg *);
|
||||
static int server_client_dispatch_shell(struct client *);
|
||||
static void server_client_report_theme(struct client *, enum client_theme);
|
||||
|
||||
/* Compare client windows. */
|
||||
static int
|
||||
server_client_window_cmp(struct client_window *cw1,
|
||||
struct client_window *cw2)
|
||||
{
|
||||
if (cw1->window < cw2->window)
|
||||
return (-1);
|
||||
if (cw1->window > cw2->window)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
RB_GENERATE(client_windows, client_window, entry, server_client_window_cmp);
|
||||
|
||||
/* Number of attached clients. */
|
||||
u_int
|
||||
server_client_how_many(void)
|
||||
@@ -188,7 +175,6 @@ server_client_create(int fd)
|
||||
c->out_fd = -1;
|
||||
|
||||
c->queue = cmdq_new();
|
||||
RB_INIT(&c->windows);
|
||||
RB_INIT(&c->files);
|
||||
|
||||
c->tty.sx = 80;
|
||||
@@ -379,8 +365,9 @@ void
|
||||
server_client_lost(struct client *c)
|
||||
{
|
||||
struct client_file *cf, *cf1;
|
||||
struct client_window *cw, *cw1;
|
||||
|
||||
if (cfg_client == c)
|
||||
cfg_client = NULL;
|
||||
c->flags |= CLIENT_DEAD;
|
||||
|
||||
status_prompt_clear(c);
|
||||
@@ -390,10 +377,6 @@ server_client_lost(struct client *c)
|
||||
cf->error = EINTR;
|
||||
file_fire_done(cf);
|
||||
}
|
||||
RB_FOREACH_SAFE(cw, client_windows, &c->windows, cw1) {
|
||||
RB_REMOVE(client_windows, &c->windows, cw);
|
||||
free(cw);
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&clients, c, entry);
|
||||
log_debug("lost client %p", c);
|
||||
@@ -1985,7 +1968,7 @@ server_client_reset_state(struct client *c)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp = server_client_get_pane(c), *loop;
|
||||
struct window_pane *wp = w->active, *loop;
|
||||
struct screen *s = NULL;
|
||||
struct options *oo = c->session->options;
|
||||
int mode = 0, cursor, flags, pane_mode = 0;
|
||||
@@ -2880,8 +2863,6 @@ server_client_set_flags(struct client *c, const char *flags)
|
||||
flag = CLIENT_READONLY;
|
||||
else if (strcmp(next, "ignore-size") == 0)
|
||||
flag = CLIENT_IGNORESIZE;
|
||||
else if (strcmp(next, "active-pane") == 0)
|
||||
flag = CLIENT_ACTIVEPANE;
|
||||
else if (strcmp(next, "no-detach-on-destroy") == 0)
|
||||
flag = CLIENT_NO_DETACH_ON_DESTROY;
|
||||
if (flag == 0)
|
||||
@@ -2930,8 +2911,6 @@ server_client_get_flags(struct client *c)
|
||||
}
|
||||
if (c->flags & CLIENT_READONLY)
|
||||
strlcat(s, "read-only,", sizeof s);
|
||||
if (c->flags & CLIENT_ACTIVEPANE)
|
||||
strlcat(s, "active-pane,", sizeof s);
|
||||
if (c->flags & CLIENT_SUSPENDED)
|
||||
strlcat(s, "suspended,", sizeof s);
|
||||
if (c->flags & CLIENT_UTF8)
|
||||
@@ -2941,83 +2920,13 @@ server_client_get_flags(struct client *c)
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* Get client window. */
|
||||
struct client_window *
|
||||
server_client_get_client_window(struct client *c, u_int id)
|
||||
{
|
||||
struct client_window cw = { .window = id };
|
||||
|
||||
return (RB_FIND(client_windows, &c->windows, &cw));
|
||||
}
|
||||
|
||||
/* Add client window. */
|
||||
struct client_window *
|
||||
server_client_add_client_window(struct client *c, u_int id)
|
||||
{
|
||||
struct client_window *cw;
|
||||
|
||||
cw = server_client_get_client_window(c, id);
|
||||
if (cw == NULL) {
|
||||
cw = xcalloc(1, sizeof *cw);
|
||||
cw->window = id;
|
||||
RB_INSERT(client_windows, &c->windows, cw);
|
||||
}
|
||||
return (cw);
|
||||
}
|
||||
|
||||
/* Get client active pane. */
|
||||
struct window_pane *
|
||||
server_client_get_pane(struct client *c)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w;
|
||||
struct client_window *cw;
|
||||
|
||||
if (s == NULL)
|
||||
return (NULL);
|
||||
|
||||
w = s->curw->window;
|
||||
if (w->modal != NULL)
|
||||
return (w->modal);
|
||||
if (~c->flags & CLIENT_ACTIVEPANE)
|
||||
return (w->active);
|
||||
cw = server_client_get_client_window(c, w->id);
|
||||
if (cw == NULL)
|
||||
return (w->active);
|
||||
return (cw->pane);
|
||||
}
|
||||
|
||||
/* Set client active pane. */
|
||||
void
|
||||
server_client_set_pane(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct client_window *cw;
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
if (wp->window->modal != NULL && wp != wp->window->modal)
|
||||
return;
|
||||
|
||||
cw = server_client_add_client_window(c, s->curw->window->id);
|
||||
cw->pane = wp;
|
||||
log_debug("%s pane now %%%u", c->name, wp->id);
|
||||
}
|
||||
|
||||
/* Remove pane from client lists. */
|
||||
/* Remove pane from client state. */
|
||||
void
|
||||
server_client_remove_pane(struct window_pane *wp)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = wp->window;
|
||||
struct client_window *cw;
|
||||
struct client *c;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
cw = server_client_get_client_window(c, w->id);
|
||||
if (cw != NULL && cw->pane == wp) {
|
||||
RB_REMOVE(client_windows, &c->windows, cw);
|
||||
free(cw);
|
||||
}
|
||||
if (c->tty.mouse_last_pane == (int)wp->id) {
|
||||
c->tty.mouse_last_pane = -1;
|
||||
c->tty.mouse_drag_update = NULL;
|
||||
@@ -3070,7 +2979,7 @@ server_client_print(struct client *c, int parse, struct evbuffer *evb)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wp = server_client_get_pane(c);
|
||||
wp = c->session->curw->window->active;
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme == NULL || wme->mode != &window_view_mode)
|
||||
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL,
|
||||
|
||||
17
tmux.1
17
tmux.1
@@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: tmux.1,v 1.1142 2026/07/15 13:02:33 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.1144 2026/07/19 17:36:38 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: July 15 2026 $
|
||||
.Dd $Mdocdate: July 19 2026 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -1112,8 +1112,6 @@ detaching the client, typically causing it to exit.
|
||||
sets a comma-separated list of client flags.
|
||||
The flags are:
|
||||
.Bl -tag -width Ds
|
||||
.It active\-pane
|
||||
the client has an independent active pane
|
||||
.It ignore\-size
|
||||
the client does not affect the size of other clients
|
||||
.It no\-detach\-on\-destroy
|
||||
@@ -1143,13 +1141,6 @@ When a client is read-only, only keys bound to the
|
||||
or
|
||||
.Ic switch\-client
|
||||
commands have any effect.
|
||||
A client with the
|
||||
.Ar active\-pane
|
||||
flag allows the active pane to be selected independently of the window's active
|
||||
pane used by clients without the flag.
|
||||
This only affects the cursor position and commands issued from the client;
|
||||
other features such as hooks and styles continue to use the window's active
|
||||
pane.
|
||||
.Pp
|
||||
If no server is started,
|
||||
.Ic attach\-session
|
||||
@@ -6573,7 +6564,7 @@ shows the subscriptions installed with
|
||||
.Sh MOUSE SUPPORT
|
||||
If the
|
||||
.Ic mouse
|
||||
option is on (the default is off),
|
||||
option is on,
|
||||
.Nm
|
||||
allows mouse events to be bound as keys.
|
||||
The name of each key is made up of a mouse event (such as
|
||||
@@ -7308,6 +7299,8 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_top" Ta "" Ta "Top of pane"
|
||||
.It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane"
|
||||
.It Li "pane_unseen_changes" Ta "" Ta "1 if there were changes in pane while in mode"
|
||||
.It Li "pane_unzoomed_height" Ta "" Ta "Height of pane when not zoomed"
|
||||
.It Li "pane_unzoomed_width" Ta "" Ta "Width of pane when not zoomed"
|
||||
.It Li "pane_width" Ta "" Ta "Width of pane"
|
||||
.It Li "pane_x" Ta "" Ta "X position of pane"
|
||||
.It Li "pane_y" Ta "" Ta "Y position of pane"
|
||||
|
||||
4
tmux.c
4
tmux.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.c,v 1.221 2026/06/29 18:17:28 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.c,v 1.222 2026/07/19 19:09:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -375,7 +375,7 @@ find_home(void)
|
||||
if (home == NULL || *home == '\0') {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw != NULL)
|
||||
home = pw->pw_dir;
|
||||
home = xstrdup(pw->pw_dir);
|
||||
else
|
||||
home = NULL;
|
||||
}
|
||||
|
||||
62
tmux.h
62
tmux.h
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.h,v 1.1406 2026/07/15 13:02:33 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1411 2026/07/20 11:16:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -809,8 +809,19 @@ struct colour_palette {
|
||||
#define GRID_LINE_EXTENDED 0x2
|
||||
#define GRID_LINE_DEAD 0x4
|
||||
#define GRID_LINE_START_PROMPT 0x8
|
||||
#define GRID_LINE_START_OUTPUT 0x10
|
||||
#define GRID_LINE_HYPERLINK 0x20
|
||||
#define GRID_LINE_SECOND_PROMPT 0x10
|
||||
#define GRID_LINE_START_COMMAND 0x20
|
||||
#define GRID_LINE_START_OUTPUT 0x40
|
||||
#define GRID_LINE_END_OUTPUT 0x80
|
||||
#define GRID_LINE_HYPERLINK 0x100
|
||||
|
||||
/* All OSC 133 flags. */
|
||||
#define GRID_LINE_OSC133_FLAGS \
|
||||
(GRID_LINE_START_PROMPT| \
|
||||
GRID_LINE_SECOND_PROMPT| \
|
||||
GRID_LINE_START_COMMAND| \
|
||||
GRID_LINE_START_OUTPUT| \
|
||||
GRID_LINE_END_OUTPUT)
|
||||
|
||||
/* Grid string flags. */
|
||||
#define GRID_STRING_WITH_SEQUENCES 0x1
|
||||
@@ -879,17 +890,27 @@ struct grid_cell_entry {
|
||||
u_char flags;
|
||||
} __packed;
|
||||
|
||||
/* OSC 133 data for a grid line. */
|
||||
struct osc133_data {
|
||||
u_short prompt_col;
|
||||
u_short cmd_col;
|
||||
u_short out_start_col;
|
||||
u_short out_end_col;
|
||||
u_char exit_status;
|
||||
};
|
||||
|
||||
/* Grid line. */
|
||||
struct grid_line {
|
||||
struct grid_cell_entry *celldata;
|
||||
u_int cellused;
|
||||
u_int cellsize;
|
||||
|
||||
struct grid_extd_entry *extddata;
|
||||
|
||||
u_short cellused;
|
||||
u_short cellsize;
|
||||
u_int extdsize;
|
||||
|
||||
int flags;
|
||||
time_t time;
|
||||
u_int time;
|
||||
struct osc133_data osc133_data;
|
||||
u_short flags;
|
||||
};
|
||||
|
||||
/* Entire grid of cells. */
|
||||
@@ -2073,18 +2094,6 @@ struct client_file {
|
||||
};
|
||||
RB_HEAD(client_files, client_file);
|
||||
|
||||
/* Client window. */
|
||||
struct client_window {
|
||||
u_int window;
|
||||
struct window_pane *pane;
|
||||
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
|
||||
RB_ENTRY(client_window) entry;
|
||||
};
|
||||
RB_HEAD(client_windows, client_window);
|
||||
|
||||
/* Maximum time to be pasting. */
|
||||
#define CLIENT_PASTE_TIME_LIMIT 5
|
||||
|
||||
@@ -2178,8 +2187,6 @@ struct client {
|
||||
const char *user;
|
||||
struct cmdq_list *queue;
|
||||
|
||||
struct client_windows windows;
|
||||
|
||||
struct control_state *control_state;
|
||||
u_int pause_age;
|
||||
|
||||
@@ -2260,7 +2267,7 @@ struct client {
|
||||
#define CLIENT_STARTSERVER 0x10000000
|
||||
#define CLIENT_REDRAWMENU 0x20000000
|
||||
#define CLIENT_NOFORK 0x40000000
|
||||
#define CLIENT_ACTIVEPANE 0x80000000ULL
|
||||
/* 0x80000000ULL unused */
|
||||
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
|
||||
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
|
||||
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
||||
@@ -3259,7 +3266,6 @@ void printflike(1, 2) server_add_message(const char *, ...);
|
||||
int server_create_socket(uint64_t, char **);
|
||||
|
||||
/* server-client.c */
|
||||
RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp);
|
||||
u_int server_client_how_many(void);
|
||||
void server_client_ensure_ranges(struct visible_ranges *, u_int);
|
||||
int server_client_ranges_is_empty(struct visible_ranges *);
|
||||
@@ -3281,10 +3287,6 @@ void server_client_loop(void);
|
||||
const char *server_client_get_cwd(struct client *, struct session *);
|
||||
void server_client_set_flags(struct client *, const char *);
|
||||
const char *server_client_get_flags(struct client *);
|
||||
struct client_window *server_client_get_client_window(struct client *, u_int);
|
||||
struct client_window *server_client_add_client_window(struct client *, u_int);
|
||||
struct window_pane *server_client_get_pane(struct client *);
|
||||
void server_client_set_pane(struct client *, struct window_pane *);
|
||||
void server_client_remove_pane(struct window_pane *);
|
||||
void server_client_print(struct client *, int, struct evbuffer *);
|
||||
|
||||
@@ -3441,6 +3443,7 @@ int grid_compare(struct grid *, struct grid *);
|
||||
const char *grid_line_flags_string(int);
|
||||
const char *grid_cell_flags_string(int);
|
||||
const char *grid_cell_attr_string(int);
|
||||
time_t grid_line_time(const struct grid_line *);
|
||||
void grid_collect_history(struct grid *, int);
|
||||
void grid_remove_history(struct grid *, u_int );
|
||||
void grid_scroll_history(struct grid *, u_int);
|
||||
@@ -3980,6 +3983,9 @@ void control_set_pane_on(struct client *, struct window_pane *);
|
||||
void control_set_pane_off(struct client *, struct window_pane *);
|
||||
void control_continue_pane(struct client *, struct window_pane *);
|
||||
void control_pause_pane(struct client *, struct window_pane *);
|
||||
void control_set_window_size(struct client *, u_int, u_int, u_int);
|
||||
int control_get_window_size(struct client *, u_int, u_int *, u_int *);
|
||||
void control_clear_window_size(struct client *, u_int);
|
||||
struct window_pane_offset *control_pane_offset(struct client *,
|
||||
struct window_pane *, int *);
|
||||
void control_reset_offsets(struct client *);
|
||||
|
||||
4
tty.c
4
tty.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty.c,v 1.476 2026/06/26 11:36:22 nicm Exp $ */
|
||||
/* $OpenBSD: tty.c,v 1.477 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -959,7 +959,7 @@ tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp = server_client_get_pane(c);
|
||||
struct window_pane *wp = w->active;
|
||||
u_int cx, cy, lines;
|
||||
|
||||
lines = status_line_size(c);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-border.c,v 1.1 2026/06/22 08:47:46 nicm Exp $ */
|
||||
/* $OpenBSD: window-border.c,v 1.2 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -93,7 +93,7 @@ window_pane_get_border_style(struct window_pane *wp, struct client *c,
|
||||
struct grid_cell *saved;
|
||||
int *flag;
|
||||
|
||||
if (wp == server_client_get_pane(c)) {
|
||||
if (wp == c->session->curw->window->active) {
|
||||
flag = &wp->active_border_gc_set;
|
||||
saved = &wp->active_border_gc;
|
||||
option = "pane-active-border-style";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-copy.c,v 1.421 2026/07/14 17:17:18 nicm Exp $ */
|
||||
/* $OpenBSD: window-copy.c,v 1.422 2026/07/20 11:16:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1107,9 +1107,11 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
|
||||
u_int hsize = screen_hsize(data->backing);
|
||||
u_int position, limit;
|
||||
struct grid_line *gl;
|
||||
time_t t;
|
||||
|
||||
gl = grid_get_line(data->backing->grid, hsize - data->oy);
|
||||
format_add(ft, "top_line_time", "%llu", (unsigned long long)gl->time);
|
||||
t = grid_line_time(gl);
|
||||
format_add(ft, "top_line_time", "%llu", (unsigned long long)t);
|
||||
|
||||
format_add(ft, "scroll_position", "%d", data->oy);
|
||||
if (window_copy_line_number_is_absolute(wme)) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-panes.c,v 1.1 2026/07/14 17:17:18 nicm Exp $ */
|
||||
/* $OpenBSD: window-panes.c,v 1.3 2026/07/19 19:53:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -57,6 +57,7 @@ struct window_panes_modedata {
|
||||
u_int source_session;
|
||||
u_int source_window;
|
||||
struct screen screen;
|
||||
struct screen *preview;
|
||||
|
||||
struct event timer;
|
||||
|
||||
@@ -103,6 +104,24 @@ window_panes_get_source(struct window_panes_modedata *data, struct session **sp,
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
window_panes_set_preview(struct window_panes_modedata *data)
|
||||
{
|
||||
struct window_pane *wp = data->wp;
|
||||
struct screen *src = &wp->base, *dst;
|
||||
struct screen_write_ctx ctx;
|
||||
u_int sx = screen_size_x(src), sy = screen_size_y(src);
|
||||
|
||||
data->preview = dst = xmalloc(sizeof *data->preview);
|
||||
screen_init(dst, sx, sy, 0);
|
||||
screen_write_start(&ctx, dst);
|
||||
screen_write_fast_copy(&ctx, src, 0, src->grid->hsize, sx, sy);
|
||||
screen_write_stop(&ctx);
|
||||
dst->mode = src->mode;
|
||||
dst->cx = src->cx;
|
||||
dst->cy = src->cy;
|
||||
}
|
||||
|
||||
static void
|
||||
window_panes_free_areas(struct window_panes_modedata *data)
|
||||
{
|
||||
@@ -379,7 +398,7 @@ window_panes_mark_pane_status_borders(u_char *map, struct window *w,
|
||||
}
|
||||
|
||||
static int
|
||||
window_panes_get_floating_frame(struct window_pane *wp, u_int osx, u_int osy,
|
||||
window_panes_get_floating_borders(struct window_pane *wp, u_int osx, u_int osy,
|
||||
u_int dsx, u_int dsy, int *xp, int *yp, int *x2p, int *y2p)
|
||||
{
|
||||
struct layout_cell *lc;
|
||||
@@ -404,12 +423,12 @@ window_panes_get_floating_frame(struct window_pane *wp, u_int osx, u_int osy,
|
||||
}
|
||||
|
||||
static int
|
||||
window_panes_clip_floating_body(struct window_pane *wp, u_int osx, u_int osy,
|
||||
window_panes_clip_floating_pane(struct window_pane *wp, u_int osx, u_int osy,
|
||||
u_int dsx, u_int dsy, u_int *xp, u_int *yp, u_int *sxp, u_int *syp)
|
||||
{
|
||||
int x, y, x2, y2, bx, by, bx2, by2;
|
||||
|
||||
if (!window_panes_get_floating_frame(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
if (!window_panes_get_floating_borders(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
&x2, &y2))
|
||||
return (1);
|
||||
|
||||
@@ -601,7 +620,7 @@ window_panes_draw_floating_border(struct screen_write_ctx *ctx,
|
||||
|
||||
if (dsx == 0 || dsy == 0)
|
||||
return;
|
||||
if (!window_panes_get_floating_frame(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
if (!window_panes_get_floating_borders(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
&x2, &y2))
|
||||
return;
|
||||
|
||||
@@ -634,7 +653,7 @@ window_panes_clear_floating_area(struct screen_write_ctx *ctx,
|
||||
struct grid_cell gc;
|
||||
int x, y, x2, y2, xx, yy;
|
||||
|
||||
if (!window_panes_get_floating_frame(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
if (!window_panes_get_floating_borders(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
&x2, &y2))
|
||||
return;
|
||||
|
||||
@@ -778,6 +797,7 @@ window_panes_draw_pane(struct window_panes_modedata *data,
|
||||
struct screen_write_ctx *ctx, struct window_pane *wp,
|
||||
struct layout_cell *root, u_int osx, u_int osy, u_int dsx, u_int dsy)
|
||||
{
|
||||
struct screen *s = &wp->base;
|
||||
u_int pane, x, y, sx, sy;
|
||||
|
||||
if (!window_panes_pane_visible(wp))
|
||||
@@ -785,7 +805,7 @@ window_panes_draw_pane(struct window_panes_modedata *data,
|
||||
if (!window_panes_get_geometry(wp, root, osx, osy, dsx, dsy, &x, &y,
|
||||
&sx, &sy))
|
||||
return;
|
||||
if (!window_panes_clip_floating_body(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
if (!window_panes_clip_floating_pane(wp, osx, osy, dsx, dsy, &x, &y,
|
||||
&sx, &sy))
|
||||
return;
|
||||
if (window_pane_index(wp, &pane) != 0)
|
||||
@@ -793,11 +813,15 @@ window_panes_draw_pane(struct window_panes_modedata *data,
|
||||
window_panes_add_area(data, wp, x, y, sx, sy);
|
||||
|
||||
screen_write_cursormove(ctx, x, y, 0);
|
||||
if (data->preview != NULL &&
|
||||
wp == data->wp &&
|
||||
sx <= screen_size_x(data->preview) &&
|
||||
sy <= screen_size_y(data->preview))
|
||||
s = data->preview;
|
||||
if (osx <= dsx && osy <= dsy)
|
||||
screen_write_fast_copy(ctx, &wp->base, 0, wp->base.grid->hsize,
|
||||
sx, sy);
|
||||
screen_write_fast_copy(ctx, s, 0, s->grid->hsize, sx, sy);
|
||||
else
|
||||
screen_write_preview(ctx, &wp->base, sx, sy);
|
||||
screen_write_preview(ctx, s, sx, sy);
|
||||
window_panes_draw_number(data, ctx, wp, pane, x, y, sx, sy);
|
||||
}
|
||||
|
||||
@@ -917,6 +941,8 @@ window_panes_init(struct window_mode_entry *wme, struct cmdq_item *item,
|
||||
data->zoomed = -1;
|
||||
else {
|
||||
data->zoomed = (w->flags & WINDOW_ZOOMED);
|
||||
if (!data->zoomed)
|
||||
window_panes_set_preview(data);
|
||||
if (!data->zoomed && window_zoom(wp) == 0)
|
||||
server_redraw_window(w);
|
||||
}
|
||||
@@ -949,6 +975,10 @@ window_panes_free(struct window_mode_entry *wme)
|
||||
if (data->state != NULL)
|
||||
args_make_commands_free(data->state);
|
||||
window_panes_free_areas(data);
|
||||
if (data->preview != NULL) {
|
||||
screen_free(data->preview);
|
||||
free(data->preview);
|
||||
}
|
||||
screen_free(&data->screen);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-visible.c,v 1.4 2026/06/29 19:03:34 nicm Exp $ */
|
||||
/* $OpenBSD: window-visible.c,v 1.5 2026/07/19 17:25:38 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -81,7 +81,7 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
|
||||
}
|
||||
|
||||
w = base_wp->window;
|
||||
if ((u_int)py >= w->sy)
|
||||
if ((u_int)py >= w->sy || (u_int)px >= w->sx)
|
||||
goto empty;
|
||||
if (px + width > w->sx)
|
||||
width = w->sx - px;
|
||||
|
||||
Reference in New Issue
Block a user