Merge branch 'master' into floating_panes

This commit is contained in:
Nicholas Marriott
2026-05-21 12:07:17 +01:00
5 changed files with 154 additions and 126 deletions

View File

@@ -1,3 +1,8 @@
CHANGES FROM 3.6a TO 3.6b
* Remove images from the correct list when they are removed while in the
alternate screen (reported by xlabai at tencent dot com).
CHANGES FROM 3.6 TO 3.6a
* Fix a buffer overread and an infinite loop in format processing (reported by

View File

@@ -29,10 +29,12 @@
static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *);
static void cmd_resize_pane_mouse_update_floating(struct client *,
struct mouse_event *);
static void cmd_resize_pane_mouse_update_tiled(struct client *,
struct mouse_event *);
static enum cmd_retval cmd_resize_pane_mouse_update(struct cmd *,
struct cmdq_item *);
static void cmd_resize_pane_mouse_update_floating(struct client *,
struct mouse_event *);
static void cmd_resize_pane_mouse_update_tiled(struct client *,
struct mouse_event *);
const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane",
@@ -53,13 +55,10 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct window_pane *wp = target->wp;
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct client *c = cmdq_get_client(item);
struct session *s = target->s;
const char *errstr;
const char *errstr;
char *cause;
u_int adjust;
int x, y, status;
@@ -77,23 +76,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) {
if (!event->m.valid)
return (CMD_RETURN_NORMAL);
wp = cmd_mouse_pane(&event->m, &s, NULL);
if (wp == NULL || c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
if (wp->flags & PANE_FLOATING) {
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_floating;
cmd_resize_pane_mouse_update_floating(c, &event->m);
} else {
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_tiled;
cmd_resize_pane_mouse_update_tiled(c, &event->m);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M'))
return (cmd_resize_pane_mouse_update(self, item));
if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED)
@@ -158,6 +142,37 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_resize_pane_mouse_update(__unused struct cmd *self, struct cmdq_item *item)
{
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct window_pane *wp = target->wp;
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct client *c = cmdq_get_client(item);
struct session *s = target->s;
if (!event->m.valid)
return (CMD_RETURN_NORMAL);
wp = cmd_mouse_pane(&event->m, &s, NULL);
if (wp == NULL || c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
if (~wp->flags & PANE_FLOATING) {
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_tiled;
cmd_resize_pane_mouse_update_tiled(c, &event->m);
return (CMD_RETURN_NORMAL);
}
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_floating;
cmd_resize_pane_mouse_update_floating(c, &event->m);
return (CMD_RETURN_NORMAL);
}
static void
cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
{
@@ -165,8 +180,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
struct window *w;
struct window_pane *wp;
struct layout_cell *lc;
u_int y, ly, x, lx;
int new_sx, new_sy;
int y, ly, x, lx, sx, sy, new_sx, new_sy;
int new_xoff, new_yoff, resizes = 0;
wp = cmd_mouse_pane(m, NULL, &wl);
@@ -176,108 +190,95 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
}
w = wl->window;
lc = wp->layout_cell;
sx = wp->sx;
sy = wp->sy;
y = m->y + m->oy; x = m->x + m->ox;
if (m->statusat == 0 && y >= m->statuslines)
if (m->statusat == 0 && y >= (int)m->statuslines)
y -= m->statuslines;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
else if (m->statusat > 0 && y >= m->statusat)
y = m->statusat - 1;
ly = m->ly + m->oy; lx = m->lx + m->ox;
if (m->statusat == 0 && ly >= (u_int)m->statuslines)
if (m->statusat == 0 && ly >= (int)m->statuslines)
ly -= m->statuslines;
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
else if (m->statusat > 0 && ly >= m->statusat)
ly = m->statusat - 1;
log_debug("%s: %%%u resize_pane xoff=%d sx=%u xy=%ux%u lxy=%ux%u",
__func__, wp->id, wp->xoff, wp->sx, x, y, lx, ly);
if ((((int)lx == wp->xoff - 1) || ((int)lx == wp->xoff)) &&
((int)ly == wp->yoff - 1)) {
/* Top left corner */
new_sx = (int)lc->sx + ((int)lx - (int)x);
if ((lx == wp->xoff - 1 || lx == wp->xoff) && ly == wp->yoff - 1) {
/* Top left corner. */
new_sx = lc->sx + (lx - x);
if (new_sx < PANE_MINIMUM)
new_sx = PANE_MINIMUM;
new_sy = (int)lc->sy + ((int)ly - (int)y);
new_sy = lc->sy + (ly - y);
if (new_sy < PANE_MINIMUM)
new_sy = PANE_MINIMUM;
new_xoff = x + 1; /* Because mouse is on border at xoff - 1 */
new_xoff = x + 1; /* because mouse is on border at xoff - 1 */
new_yoff = y + 1;
layout_set_size(lc, (u_int)new_sx, (u_int)new_sy, new_xoff, new_yoff);
layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff);
resizes++;
} else if ((((int)lx == wp->xoff + (int)wp->sx + 1) ||
((int)lx == wp->xoff + (int)wp->sx)) &&
((int)ly == wp->yoff - 1)) {
/* Top right corner */
new_sx = (int)x - lc->xoff;
} else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) &&
ly == wp->yoff - 1) {
/* Top right corner. */
new_sx = x - lc->xoff;
if (new_sx < PANE_MINIMUM)
new_sx = PANE_MINIMUM;
new_sy = (int)lc->sy + ((int)ly - (int)y);
new_sy = lc->sy + (ly - y);
if (new_sy < PANE_MINIMUM)
new_sy = PANE_MINIMUM;
new_yoff = y + 1;
layout_set_size(lc, (u_int)new_sx, (u_int)new_sy, lc->xoff, new_yoff);
layout_set_size(lc, new_sx, new_sy, lc->xoff, new_yoff);
resizes++;
} else if ((((int)lx == wp->xoff - 1) || ((int)lx == wp->xoff)) &&
((int)ly == wp->yoff + (int)wp->sy)) {
/* Bottom left corner */
new_sx = (int)lc->sx + ((int)lx - (int)x);
} else if ((lx == wp->xoff - 1 || lx == wp->xoff) &&
ly == wp->yoff + sy) {
/* Bottom left corner. */
new_sx = lc->sx + (lx - x);
if (new_sx < PANE_MINIMUM)
new_sx = PANE_MINIMUM;
new_sy = (int)y - lc->yoff;
new_sy = y - lc->yoff;
if (new_sy < PANE_MINIMUM)
return;
new_xoff = x + 1;
layout_set_size(lc, (u_int)new_sx, (u_int)new_sy, new_xoff, lc->yoff);
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->yoff);
resizes++;
} else if ((((int)lx == wp->xoff + (int)wp->sx + 1) ||
((int)lx == wp->xoff + (int)wp->sx)) &&
((int)ly == wp->yoff + (int)wp->sy)) {
/* Bottom right corner */
new_sx = (int)x - lc->xoff;
} else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) &&
ly == wp->yoff + sy) {
/* Bottom right corner. */
new_sx = x - lc->xoff;
if (new_sx < PANE_MINIMUM)
new_sx = PANE_MINIMUM;
new_sy = (int)y - lc->yoff;
new_sy = y - lc->yoff;
if (new_sy < PANE_MINIMUM)
new_sy = PANE_MINIMUM;
layout_set_size(lc, (u_int)new_sx, (u_int)new_sy, lc->xoff, lc->yoff);
layout_set_size(lc, new_sx, new_sy, lc->xoff, lc->yoff);
resizes++;
} else if ((int)lx == wp->xoff + (int)wp->sx + 1) {
/* Right border */
new_sx = (int)x - lc->xoff;
} else if (lx == wp->xoff + sx + 1) {
/* Right border. */
new_sx = x - lc->xoff;
if (new_sx < PANE_MINIMUM)
return;
layout_set_size(lc, (u_int)new_sx, lc->sy, lc->xoff, lc->yoff);
layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff);
resizes++;
} else if ((int)lx == wp->xoff - 1) {
/* Left border */
new_sx = (int)lc->sx + ((int)lx - (int)x);
} else if (lx == wp->xoff - 1) {
/* Left border. */
new_sx = lc->sx + (lx - x);
if (new_sx < PANE_MINIMUM)
return;
new_xoff = x + 1;
layout_set_size(lc, (u_int)new_sx, lc->sy, new_xoff, lc->yoff);
layout_set_size(lc, new_sx, lc->sy, new_xoff, lc->yoff);
resizes++;
} else if ((int)ly == wp->yoff + (int)wp->sy) {
/* Bottom border */
new_sy = (int)y - lc->yoff;
} else if (ly == wp->yoff + sy) {
/* Bottom border. */
new_sy = y - lc->yoff;
if (new_sy < PANE_MINIMUM)
return;
layout_set_size(lc, lc->sx, (u_int)new_sy, lc->xoff, lc->yoff);
layout_set_size(lc, lc->sx, new_sy, lc->xoff, lc->yoff);
resizes++;
} else if ((int)ly == wp->yoff - 1) {
/* Top border (move instead of resize) */
new_xoff = lc->xoff + ((int)x - (int)lx);
} else if (ly == wp->yoff - 1) {
/* Top border (move instead of resize). */
new_xoff = lc->xoff + (x - lx);
new_yoff = y + 1;
layout_set_size(lc, lc->sx, lc->sy, new_xoff, new_yoff);
/* To resize instead of move:
new_sy = wp->sy + (ly - y);
if (new_sy < PANE_MINIMUM)
return;
new_yoff = y + 1;
layout_set_size(lc, lc->sx, new_sy, lc->xoff, new_yoff);
*/
resizes++;
} else {
log_debug("%s: %%%u resize_pane xoff=%d sx=%u xy=%ux%u lxy=%ux%u <else>",
__func__, wp->id, wp->xoff, wp->sx, x, y, lx, ly);
}
if (resizes != 0) {
layout_fix_panes(w, NULL);
@@ -292,7 +293,7 @@ cmd_resize_pane_mouse_update_tiled(struct client *c, struct mouse_event *m)
struct winlink *wl;
struct window *w;
u_int y, ly, x, lx;
static const int offsets[][2] = {
static const int offsets[][2] = {
{ 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
};
struct layout_cell *cells[nitems(offsets)], *lc;

View File

@@ -599,7 +599,7 @@ server_client_exec(struct client *c, const char *cmd)
}
static enum key_code_mouse_location
server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py,
server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
u_int *sl_mpos)
{
struct window *w = wp->window;
@@ -630,36 +630,35 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py,
/* Check if point is within the pane or scrollbar. */
if (((pane_status != PANE_STATUS_OFF &&
(int)py != pane_status_line && (int)py != wp->yoff + (int)wp->sy) ||
(wp->yoff == 0 && py < wp->sy) ||
((int)py >= wp->yoff && (int)py < wp->yoff + (int)wp->sy)) &&
py != pane_status_line && py != wp->yoff + (int)wp->sy) ||
(wp->yoff == 0 && py < (int)wp->sy) ||
(py >= wp->yoff && py < wp->yoff + (int)wp->sy)) &&
((sb_pos == PANE_SCROLLBARS_RIGHT &&
(int)px < (int)wp->xoff + (int)wp->sx + sb_pad + sb_w) ||
px < wp->xoff + (int)wp->sx + sb_pad + sb_w) ||
(sb_pos == PANE_SCROLLBARS_LEFT &&
(int)px < (int)wp->xoff + (int)wp->sx - sb_pad - sb_w))) {
px < wp->xoff + (int)wp->sx - sb_pad - sb_w))) {
/* Check if in the scrollbar. */
if ((sb_pos == PANE_SCROLLBARS_RIGHT &&
((int)px >= (int)wp->xoff + (int)wp->sx + sb_pad &&
(int)px < (int)wp->xoff + (int)wp->sx + sb_pad + sb_w)) ||
(px >= wp->xoff + (int)wp->sx + sb_pad &&
px < wp->xoff + (int)wp->sx + sb_pad + sb_w)) ||
(sb_pos == PANE_SCROLLBARS_LEFT &&
((int)px >= (int)wp->xoff - sb_pad - sb_w &&
(int)px < (int)wp->xoff - sb_pad))) {
(px >= wp->xoff - sb_pad - sb_w &&
px < wp->xoff - sb_pad))) {
/* Check where inside the scrollbar. */
sl_top = wp->yoff + wp->sb_slider_y;
sl_bottom = (wp->yoff + wp->sb_slider_y +
wp->sb_slider_h - 1);
if ((int)py < sl_top)
if (py < sl_top)
return (KEYC_MOUSE_LOCATION_SCROLLBAR_UP);
else if ((int)py >= sl_top &&
(int)py <= sl_bottom) {
else if (py >= sl_top && py <= sl_bottom) {
*sl_mpos = (py - wp->sb_slider_y - wp->yoff);
return (KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER);
} else /* py > sl_bottom */
return (KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN);
} else if (wp->flags & PANE_FLOATING &&
((int)px == wp->xoff - 1 ||
(int)py == wp->yoff - 1 ||
(int)py == wp->yoff + (int)wp->sy)) {
(px == wp->xoff - 1 ||
py == wp->yoff - 1 ||
py == wp->yoff + (int)wp->sy)) {
/* Floating pane left, bottom or top border. */
return (KEYC_MOUSE_LOCATION_BORDER);
} else {
@@ -673,33 +672,33 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py,
(~fwp->flags & PANE_ZOOMED))
continue;
bdr_top = fwp->yoff - 1;
bdr_bottom = fwp->yoff + (int)fwp->sy;
bdr_bottom = fwp->yoff + fwp->sy;
if (sb_pos == PANE_SCROLLBARS_LEFT)
bdr_right = fwp->xoff + (int)fwp->sx;
else
bdr_right = fwp->xoff + fwp->sx;
else {
/* PANE_SCROLLBARS_RIGHT or none. */
bdr_right = fwp->xoff + (int)fwp->sx +
sb_pad + sb_w;
if ((int)py >= fwp->yoff - 1 &&
(int)py <= fwp->yoff + (int)fwp->sy) {
if ((int)px == bdr_right)
bdr_right = fwp->xoff + fwp->sx + sb_pad + sb_w;
}
if (py >= fwp->yoff - 1 &&
py <= fwp->yoff + (int)fwp->sy) {
if (px == bdr_right)
break;
if (wp->flags & PANE_FLOATING) {
/* Floating pane, check if left border. */
/* Floating pane, check left border. */
bdr_left = fwp->xoff - 1;
if ((int)px == bdr_left)
if (px == bdr_left)
break;
}
}
if ((int)px >= fwp->xoff - 1 &&
(int)px <= fwp->xoff + (int)fwp->sx) {
bdr_bottom = fwp->yoff + (int)fwp->sy;
if ((int)py == bdr_bottom)
if (px >= fwp->xoff - 1 &&
px <= fwp->xoff + (int)fwp->sx) {
bdr_bottom = fwp->yoff + fwp->sy;
if (py == bdr_bottom)
break;
if (wp->flags & PANE_FLOATING) {
/* Floating pane, check if top border. */
/* Floating pane, check top border. */
bdr_top = fwp->yoff - 1;
if ((int)py == bdr_top)
if (py == bdr_top)
break;
}
}
@@ -989,7 +988,7 @@ have_event:
type = KEYC_TYPE_MOUSEDRAGEND;
c->tty.mouse_drag_flag = 0;
c->tty.mouse_slider_mpos = -1;
c->tty.mouse_last_pane = -1;
c->tty.mouse_last_pane = -1;
}
/* Convert to a key binding. */
@@ -998,7 +997,7 @@ have_event:
if (wp != NULL &&
wp != w->active &&
options_get_number(s->options, "focus-follows-mouse")) {
window_redraw_active_switch(w, wp); /* xxx needed? */
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
server_redraw_window_borders(w);
server_status_window(w);
@@ -1799,6 +1798,7 @@ server_client_reset_state(struct client *c)
struct options *oo = c->session->options;
int mode = 0, cursor, flags;
u_int cx = 0, cy = 0, ox, oy, sx, sy, n;
struct visible_ranges *r;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
@@ -1848,14 +1848,14 @@ server_client_reset_state(struct client *c)
wp->yoff + (int)s->cy <= (int)oy + (int)sy) {
cursor = 1;
cx = (u_int)(wp->xoff + (int)s->cx - (int)ox);
cy = (u_int)(wp->yoff + (int)s->cy - (int)oy);
cx = wp->xoff + (int)s->cx - (int)ox;
cy = wp->yoff + (int)s->cy - (int)oy;
if (status_at_line(c) == 0)
cy += status_line_size(c);
}
if (!screen_redraw_is_visible(
screen_redraw_get_visible_ranges(wp, cx, cy, 1, NULL), cx))
r = screen_redraw_get_visible_ranges(wp, cx, cy, 1, NULL);
if (!screen_redraw_is_visible(r, cx))
cursor = 0;
if (!cursor)

3
tmux.h
View File

@@ -1707,6 +1707,7 @@ struct tty {
#define TTY_WINSIZEQUERY 0x1000
#define TTY_WAITFG 0x2000
#define TTY_WAITBG 0x4000
#define TTY_BRACKETPASTE 0x8000
#define TTY_ALL_REQUEST_FLAGS \
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)
int flags;
@@ -1719,7 +1720,7 @@ struct tty {
int mouse_drag_flag;
int mouse_scrolling_flag;
int mouse_slider_mpos;
int mouse_last_pane;
int mouse_last_pane;
void (*mouse_drag_update)(struct client *,
struct mouse_event *);
void (*mouse_drag_release)(struct client *,

View File

@@ -605,6 +605,17 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
return (tty_keys_find1(tk, buf, len, size));
}
static int
tty_keys_partial_paste_end(const char *buf, size_t len)
{
static const char paste_end[] = "\033[201~";
size_t paste_end_len = (sizeof paste_end) - 1;
if (len == 0 || len >= paste_end_len)
return (0);
return (memcmp(buf, paste_end, len) == 0);
}
/* Look up part of the next key. */
static int
tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
@@ -630,6 +641,10 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
if (tk->next != NULL && !expired)
return (1);
*key = tk->key;
if ((*key & KEYC_MASK_KEY) == KEYC_PASTE_START)
tty->flags |= TTY_BRACKETPASTE;
else if ((*key & KEYC_MASK_KEY) == KEYC_PASTE_END)
tty->flags &= ~TTY_BRACKETPASTE;
return (0);
}
@@ -955,10 +970,16 @@ partial_key:
delay = options_get_number(global_options, "escape-time");
if (delay == 0)
delay = 1;
if ((tty->flags & TTY_BRACKETPASTE) &&
tty_keys_partial_paste_end(buf, len)) {
log_debug("%s: increasing delay (partial paste end)", c->name);
if (delay < 500)
delay = 500;
}
if ((tty->flags & (TTY_WAITFG|TTY_WAITBG) ||
(tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS) ||
!TAILQ_EMPTY(&c->input_requests)) {
log_debug("%s: increasing delay for active query", c->name);
log_debug("%s: increasing delay (active query)", c->name);
if (delay < 500)
delay = 500;
}