Merge branch 'master' into floating_panes

This commit is contained in:
Dane Jensen
2026-06-16 13:38:33 -07:00
14 changed files with 381 additions and 276 deletions

View File

@@ -217,6 +217,7 @@ dist_tmux_SOURCES = \
window-copy.c \ window-copy.c \
window-customize.c \ window-customize.c \
window-tree.c \ window-tree.c \
window-visible.c \
window.c \ window.c \
xmalloc.c \ xmalloc.c \
xmalloc.h xmalloc.h

View File

@@ -114,7 +114,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
w->active = wp; w->active = wp;
w->latest = tc; w->latest = tc;
if (name != NULL) { if (name == NULL) {
newname = default_window_name(w); newname = default_window_name(w);
window_set_name(w, newname, WINDOW_NAME_FORBID); window_set_name(w, newname, WINDOW_NAME_FORBID);
free(newname); free(newname);

View File

@@ -65,8 +65,7 @@ cmd_display_panes_put(struct screen_redraw_ctx *ctx,
struct visible_range *ri; struct visible_range *ri;
u_int i, j; u_int i, j;
r = screen_redraw_get_visible_ranges(wp, ctx->ox + cx, ctx->oy + cy, r = window_visible_ranges(wp, ctx->ox + cx, ctx->oy + cy, len, NULL);
len, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
for (j = ri->px; j < ri->px + ri->nx; j++) { for (j = ri->px; j < ri->px + ri->nx; j++) {
@@ -103,7 +102,7 @@ cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx,
screen_write_stop(&sctx); screen_write_stop(&sctx);
free(expanded); free(expanded);
r = screen_redraw_get_visible_ranges(wp, px, wp->yoff, sx, NULL); r = window_visible_ranges(wp, px, wp->yoff, sx, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
tty_draw_line(tty, &screen, ri->px - px, 0, ri->nx, tty_draw_line(tty, &screen, ri->px - px, 0, ri->nx,

View File

@@ -61,7 +61,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = target->s; struct session *s = target->s;
struct winlink *wl = target->wl, *new_wl = NULL; struct winlink *wl = target->wl, *new_wl = NULL;
int idx = target->idx, before; int idx = target->idx, before;
char *cause = NULL, *cp, *expanded, *wname; char *cause = NULL, *cp, *expanded, *wname = NULL;
const char *template, *name; const char *template, *name;
struct cmd_find_state fs; struct cmd_find_state fs;
struct args_value *av; struct args_value *av;

View File

@@ -226,6 +226,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc; struct layout_cell *lc;
int y, ly, x, lx, sx, sy, new_sx, new_sy; int y, ly, x, lx, sx, sy, new_sx, new_sy;
int scrollbars, sb_pos, left, right;
int new_xoff, new_yoff, resizes = 0; int new_xoff, new_yoff, resizes = 0;
wp = cmd_mouse_pane(m, NULL, &wl); wp = cmd_mouse_pane(m, NULL, &wl);
@@ -237,6 +238,17 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
lc = wp->layout_cell; lc = wp->layout_cell;
sx = wp->sx; sx = wp->sx;
sy = wp->sy; sy = wp->sy;
scrollbars = options_get_number(w->options, "pane-scrollbars");
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
left = wp->xoff - 1;
right = wp->xoff + sx;
if (window_pane_show_scrollbar(wp, scrollbars) &&
sb_pos == PANE_SCROLLBARS_LEFT) {
left -= wp->scrollbar_style.width + wp->scrollbar_style.pad;
} else if (window_pane_show_scrollbar(wp, scrollbars) &&
sb_pos == PANE_SCROLLBARS_RIGHT) {
right += wp->scrollbar_style.width + wp->scrollbar_style.pad;
}
y = m->y + m->oy; x = m->x + m->ox; y = m->y + m->oy; x = m->x + m->ox;
if (m->statusat == 0 && y >= (int)m->statuslines) if (m->statusat == 0 && y >= (int)m->statuslines)
@@ -249,7 +261,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
else if (m->statusat > 0 && ly >= m->statusat) else if (m->statusat > 0 && ly >= m->statusat)
ly = m->statusat - 1; ly = m->statusat - 1;
if ((lx == wp->xoff - 1 || lx == wp->xoff) && ly == wp->yoff - 1) { if ((lx == left || lx == left + 1) && ly == wp->yoff - 1) {
/* Top left corner. */ /* Top left corner. */
new_sx = lc->sx + (lx - x); new_sx = lc->sx + (lx - x);
if (new_sx < PANE_MINIMUM) if (new_sx < PANE_MINIMUM)
@@ -261,7 +273,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
new_yoff = y + 1; new_yoff = y + 1;
layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff); layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff);
resizes++; resizes++;
} else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) && } else if ((lx == right + 1 || lx == right) &&
ly == wp->yoff - 1) { ly == wp->yoff - 1) {
/* Top right corner. */ /* Top right corner. */
new_sx = x - lc->xoff; new_sx = x - lc->xoff;
@@ -273,7 +285,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
new_yoff = y + 1; new_yoff = y + 1;
layout_set_size(lc, new_sx, new_sy, lc->xoff, new_yoff); layout_set_size(lc, new_sx, new_sy, lc->xoff, new_yoff);
resizes++; resizes++;
} else if ((lx == wp->xoff - 1 || lx == wp->xoff) && } else if ((lx == left || lx == left + 1) &&
ly == wp->yoff + sy) { ly == wp->yoff + sy) {
/* Bottom left corner. */ /* Bottom left corner. */
new_sx = lc->sx + (lx - x); new_sx = lc->sx + (lx - x);
@@ -285,7 +297,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
new_xoff = x + 1; new_xoff = x + 1;
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->yoff); layout_set_size(lc, new_sx, new_sy, new_xoff, lc->yoff);
resizes++; resizes++;
} else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) && } else if ((lx == right + 1 || lx == right) &&
ly == wp->yoff + sy) { ly == wp->yoff + sy) {
/* Bottom right corner. */ /* Bottom right corner. */
new_sx = x - lc->xoff; new_sx = x - lc->xoff;
@@ -296,14 +308,14 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
new_sy = PANE_MINIMUM; new_sy = PANE_MINIMUM;
layout_set_size(lc, new_sx, new_sy, lc->xoff, lc->yoff); layout_set_size(lc, new_sx, new_sy, lc->xoff, lc->yoff);
resizes++; resizes++;
} else if (lx == wp->xoff + sx + 1) { } else if (lx == right) {
/* Right border. */ /* Right border. */
new_sx = x - lc->xoff; new_sx = x - lc->xoff;
if (new_sx < PANE_MINIMUM) if (new_sx < PANE_MINIMUM)
return; return;
layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff); layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff);
resizes++; resizes++;
} else if (lx == wp->xoff - 1) { } else if (lx == left) {
/* Left border. */ /* Left border. */
new_sx = lc->sx + (lx - x); new_sx = lc->sx + (lx - x);
if (new_sx < PANE_MINIMUM) if (new_sx < PANE_MINIMUM)

View File

@@ -297,24 +297,24 @@ fi
# Look for ncurses or curses. Try pkg-config first then directly for the # Look for ncurses or curses. Try pkg-config first then directly for the
# library. # library.
PKG_CHECK_MODULES( PKG_CHECK_MODULES(
LIBTINFO, LIBTINFOW,
tinfo, tinfow,
[ [
AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS" AM_CPPFLAGS="$LIBTINFOW_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS" CPPFLAGS="$LIBTINFOW_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBTINFO_LIBS $LIBS" LIBS="$LIBTINFOW_LIBS $LIBS"
found_ncurses=yes found_ncurses=yes
], ],
found_ncurses=no found_ncurses=no
) )
if test "x$found_ncurses" = xno; then if test "x$found_ncurses" = xno; then
PKG_CHECK_MODULES( PKG_CHECK_MODULES(
LIBNCURSES, LIBTINFO,
ncurses, tinfo,
[ [
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS" AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS" CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBNCURSES_LIBS $LIBS" LIBS="$LIBTINFO_LIBS $LIBS"
found_ncurses=yes found_ncurses=yes
], ],
found_ncurses=no found_ncurses=no
@@ -333,10 +333,23 @@ if test "x$found_ncurses" = xno; then
found_ncurses=no found_ncurses=no
) )
fi fi
if test "x$found_ncurses" = xno; then
PKG_CHECK_MODULES(
LIBNCURSES,
ncurses,
[
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBNCURSES_LIBS $LIBS"
found_ncurses=yes
],
found_ncurses=no
)
fi
if test "x$found_ncurses" = xno; then if test "x$found_ncurses" = xno; then
AC_SEARCH_LIBS( AC_SEARCH_LIBS(
setupterm, setupterm,
[tinfo terminfo ncurses ncursesw], [tinfow tinfo terminfo ncursesw ncurses],
found_ncurses=yes, found_ncurses=yes,
found_ncurses=no found_ncurses=no
) )

View File

@@ -28,10 +28,10 @@
* left-right container for a list of cells, a top-bottom container for a list * left-right container for a list of cells, a top-bottom container for a list
* of cells, or a container for a window pane. 'Node' will be used to refer to * of cells, or a container for a window pane. 'Node' will be used to refer to
* a cell which contains a list of cells, and 'leaf' to refer to a cell that * a cell which contains a list of cells, and 'leaf' to refer to a cell that
* contains a window pane. A leaf is considered to be tiled if it is to be drawn * contains a window pane. A leaf is considered to be 'tiled' if it is to be
* as a part of the tiled layout. A 'neighbour' is a sibling that is also tiled. * drawn as a part of the tiled layout. A 'neighbour' is a sibling that is also
* A cell's 'split' size refers to the side that is shortened when splitting it, * tiled. A cell's 'split' size refers to the side that is shortened when
* determined by the parent's type. * splitting it, determined by the parent's type.
* *
* Each window has a pointer to the root of its layout tree (containing its * Each window has a pointer to the root of its layout tree (containing its
* panes), every pane has a pointer back to the cell containing it, and each * panes), every pane has a pointer back to the cell containing it, and each
@@ -264,6 +264,49 @@ layout_fix_zindexes(struct window *w, struct layout_cell *lc)
} }
} }
static int
layout_cell_is_tiled(struct layout_cell *lc)
{
int is_leaf = lc->type == LAYOUT_WINDOWPANE;
int is_floating = lc->flags & LAYOUT_CELL_FLOATING;
return is_leaf && !is_floating;
}
static int
layout_cell_has_tiled_child(struct layout_cell *lc)
{
struct layout_cell *lcchild;
if (lc->type == LAYOUT_WINDOWPANE)
return (0);
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (layout_cell_is_tiled(lcchild) ||
layout_cell_has_tiled_child(lcchild))
return (1);
}
return (0);
}
static int
layout_cell_is_first_tiled(struct layout_cell *lc)
{
struct layout_cell *lcchild, *lcparent = lc->parent;
if (lcparent == NULL)
return (layout_cell_is_tiled(lc));
TAILQ_FOREACH(lcchild, &lcparent->cells, entry) {
if (layout_cell_is_tiled(lcchild) ||
layout_cell_has_tiled_child(lcchild))
break;
}
return (lcchild == lc);
}
/* Fix cell offsets for a child cell. */ /* Fix cell offsets for a child cell. */
static void static void
layout_fix_offsets1(struct layout_cell *lc) layout_fix_offsets1(struct layout_cell *lc)
@@ -725,8 +768,10 @@ out:
lc->parent = lcparent->parent; lc->parent = lcparent->parent;
if (lc->parent == NULL) { if (lc->parent == NULL) {
if (layout_cell_is_tiled(lc)) if (layout_cell_is_tiled(lc)) {
layout_set_size(lc, w->sx, w->sy, 0, 0); lc->xoff = 0;
lc->yoff = 0;
}
*lcroot = lc; *lcroot = lc;
} else } else
TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);

View File

@@ -129,7 +129,7 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
int hsplit = 0, vsplit = 0; int hsplit = 0, vsplit = 0;
int pane_status = window_pane_get_pane_status(wp); int pane_status = window_pane_get_pane_status(wp);
int pane_scrollbars = ctx->pane_scrollbars, sb_w = 0; int pane_scrollbars = ctx->pane_scrollbars, sb_w = 0;
int sb_pos, sx = wp->sx, sy = wp->sy; int sb_pos, sx = wp->sx, sy = wp->sy, left, right;
enum layout_type split_type; enum layout_type split_type;
if (pane_scrollbars != 0) if (pane_scrollbars != 0)
@@ -151,20 +151,19 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
/* Floating pane borders. */ /* Floating pane borders. */
if (window_pane_is_floating(wp)) { if (window_pane_is_floating(wp)) {
left = wp->xoff - 1;
right = wp->xoff + sx;
if (sb_pos == PANE_SCROLLBARS_LEFT)
left -= sb_w;
else
right += sb_w;
if (py >= wp->yoff - 1 && py <= wp->yoff + sy) { if (py >= wp->yoff - 1 && py <= wp->yoff + sy) {
if (sb_pos == PANE_SCROLLBARS_LEFT) { if (px == left)
if (px == wp->xoff - 1 - sb_w) return (SCREEN_REDRAW_BORDER_LEFT);
return (SCREEN_REDRAW_BORDER_LEFT); if (px == right)
if (px == wp->xoff + sx) return (SCREEN_REDRAW_BORDER_RIGHT);
return (SCREEN_REDRAW_BORDER_RIGHT);
} else { /* PANE_SCROLLBARS_RIGHT or none. */
if (px == wp->xoff - 1)
return (SCREEN_REDRAW_BORDER_LEFT);
if (px == wp->xoff + sx + sb_w)
return (SCREEN_REDRAW_BORDER_RIGHT);
}
} }
if (px >= wp->xoff && px <= wp->xoff + sx) { if (px > left && px <= right) {
if (py == wp->yoff - 1) if (py == wp->yoff - 1)
return (SCREEN_REDRAW_BORDER_TOP); return (SCREEN_REDRAW_BORDER_TOP);
if (py == wp->yoff + sy) if (py == wp->yoff + sy)
@@ -737,7 +736,7 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
} }
r = tty_check_overlay_range(tty, x, yoff, width); r = tty_check_overlay_range(tty, x, yoff, width);
r = screen_redraw_get_visible_ranges(wp, x, yoff, width, r); r = window_visible_ranges(wp, x, yoff, width, r);
if (ctx->statustop) if (ctx->statustop)
yoff += ctx->statuslines; yoff += ctx->statuslines;
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
@@ -1128,205 +1127,6 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i, NULL); tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i, NULL);
} }
/*
* Check if a single character is within a visible range (not obscured by a
* floating pane).
*/
int
screen_redraw_is_visible(struct visible_ranges *r, u_int px)
{
u_int i;
struct visible_range *ri;
if (r == NULL)
return (1);
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
if (ri->nx != 0 && px >= ri->px && px < ri->px + ri->nx)
return (1);
}
return (0);
}
/*
* Construct ranges array for the line at starting at px,py of width cells of
* base_wp that are unobsructed. All ranges are in window coordinates.
*/
struct visible_ranges *
screen_redraw_get_visible_ranges(struct window_pane *base_wp, int px,
int py, u_int width, struct visible_ranges *r)
{
struct window_pane *wp;
struct window *w;
struct visible_range *ri;
static struct visible_ranges sr = { NULL, 0, 0 };
int found_self, sb, sb_w, sb_pos, no_border;
int lb, rb, tb, bb, sx, ex;
u_int i, s;
if (py < 0 || width == 0)
goto empty;
if (px < 0) {
if ((u_int)-px >= width)
goto empty;
width -= (u_int)-px;
px = 0;
}
if (base_wp == NULL) {
if (r != NULL)
return (r);
if (sr.ranges == NULL)
sr.ranges = xcalloc(1, sizeof *sr.ranges);
sr.ranges[0].px = px;
sr.ranges[0].nx = width;
sr.size = 1;
sr.used = 1;
return (&sr);
}
w = base_wp->window;
if ((u_int)py >= w->sy)
goto empty;
if (px + width > w->sx)
width = w->sx - px;
if (r == NULL) {
/* Start with the entire width of the range. */
server_client_ensure_ranges(&base_wp->r, 1);
r = &base_wp->r;
r->ranges[0].px = px;
r->ranges[0].nx = width;
r->used = 1;
}
sb = options_get_number(w->options, "pane-scrollbars");
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
found_self = 0;
TAILQ_FOREACH_REVERSE(wp, &w->z_index, window_panes_zindex, zentry) {
if (wp == base_wp) {
found_self = 1;
continue;
}
if (window_pane_is_floating(wp) &&
window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
no_border = 1;
else
no_border = 0;
if (no_border) {
tb = wp->yoff;
bb = wp->yoff + (int)wp->sy - 1;
} else {
tb = wp->yoff > 0 ? wp->yoff - 1 : 0;
bb = wp->yoff + (int)wp->sy;
}
if (!found_self ||
!window_pane_is_visible(wp) ||
py < tb ||
py > bb)
continue;
if (!window_pane_is_floating(wp) && (py == tb || py == bb))
continue;
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
if (!window_pane_show_scrollbar(wp, sb))
sb_w = sb_pos = 0;
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
if (no_border) {
lb = wp->xoff;
rb = wp->xoff + (int)wp->sx - 1;
} else if (sb_pos == PANE_SCROLLBARS_LEFT) {
if (wp->xoff > sb_w)
lb = wp->xoff - 1 - sb_w;
else
lb = 0;
} else { /* PANE_SCROLLBARS_RIGHT or none. */
if (wp->xoff > 0)
lb = wp->xoff - 1;
else
lb = 0;
}
if (!no_border) {
if (sb_pos == PANE_SCROLLBARS_LEFT)
rb = wp->xoff + (int)wp->sx;
else /* PANE_SCROLLBARS_RIGHT or none. */
rb = wp->xoff + (int)wp->sx + sb_w;
}
if (lb < 0)
lb = 0;
if (rb < 0)
continue;
if (no_border && rb >= (int)w->sx)
rb = w->sx - 1;
else if (!no_border && rb > (int)w->sx)
rb = w->sx - 1;
sx = ri->px;
ex = sx + ri->nx - 1;
if (lb > sx && lb <= ex && rb > ex) {
/*
* If the left edge of floating pane falls
* inside this range and right edge covers up
* to right of range, then shrink left edge of
* range.
*/
ri->nx = lb - sx;
} else if (rb >= sx && rb <= ex && lb <= sx) {
/*
* Else if the right edge of floating pane falls
* inside of this range and left edge covers
* the left of range, then move px forward to
* right edge of pane.
*/
ri->nx = ex - rb;
ri->px = rb + 1;
} else if (lb > sx && rb <= ex) {
/*
* Else if pane fully inside range then split
* into 2 ranges.
*/
server_client_ensure_ranges(r, r->used + 1);
for (s = r->used; s > i; s--) {
memcpy(&r->ranges[s], &r->ranges[s - 1],
sizeof *r->ranges);
}
ri = &r->ranges[i];
r->ranges[i + 1].px = rb + 1;
r->ranges[i + 1].nx = ex - rb;
/* ri->px was copied, unchanged. */
ri->nx = lb - sx;
r->used++;
} else if (lb <= sx && rb > ex) {
/*
* If floating pane completely covers this range
* then delete it (make it 0 length).
*/
ri->nx = 0;
} else {
/*
* The range is already obscured, do
* nothing.
*/
}
}
}
return (r);
empty:
if (r == NULL) {
if (sr.ranges == NULL)
sr.ranges = xcalloc(1, sizeof *sr.ranges);
sr.size = 1;
sr.used = 0;
return (&sr);
}
r->used = 0;
return (r);
}
/* Draw one pane. */ /* Draw one pane. */
static void static void
@@ -1421,7 +1221,7 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
/* Get visible ranges of line before we draw it. */ /* Get visible ranges of line before we draw it. */
r = tty_check_overlay_range(tty, wx, wy, width); r = tty_check_overlay_range(tty, wx, wy, width);
r = screen_redraw_get_visible_ranges(wp, wx, wy, width, r); r = window_visible_ranges(wp, wx, wy, width, r);
for (k = 0; k < r->used; k++) { for (k = 0; k < r->used; k++) {
ri = &r->ranges[k]; ri = &r->ranges[k];
if (ri->nx == 0) if (ri->nx == 0)
@@ -1595,7 +1395,7 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
wy = sb_wy + j; /* window y coordinate */ wy = sb_wy + j; /* window y coordinate */
py = sb_tty_y + j; /* tty y coordinate */ py = sb_tty_y + j; /* tty y coordinate */
r = tty_check_overlay_range(tty, sb_x, wy, imax); r = tty_check_overlay_range(tty, sb_x, wy, imax);
r = screen_redraw_get_visible_ranges(wp, sb_x, wy, imax, r); r = window_visible_ranges(wp, sb_x, wy, imax, r);
for (i = imin; i < imax; i++) { for (i = imin; i < imax; i++) {
px = sb_x + ox + i; /* tty x coordinate */ px = sb_x + ox + i; /* tty x coordinate */
wx = sb_x + i; /* window x coordinate */ wx = sb_x + i; /* window x coordinate */
@@ -1603,7 +1403,7 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
px >= sx || px < 0 || px >= sx || px < 0 ||
wy < yoff - 1 || wy < yoff - 1 ||
py >= sy || py < 0 || py >= sy || py < 0 ||
!screen_redraw_is_visible(r, wx)) !window_position_is_visible(r, wx))
continue; continue;
tty_cursor(tty, px, py); tty_cursor(tty, px, py);
if ((sb_pos == PANE_SCROLLBARS_LEFT && if ((sb_pos == PANE_SCROLLBARS_LEFT &&

View File

@@ -647,8 +647,8 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
break; break;
s->cx = cx; s->cx = cx;
screen_write_initctx(ctx, &ttyctx, 0, 0); screen_write_initctx(ctx, &ttyctx, 0, 0);
r = screen_redraw_get_visible_ranges(wp, xoff + s->cx, r = window_visible_ranges(wp, xoff + s->cx, s->cy + yoff, nx,
s->cy + yoff, nx, NULL); NULL);
for (xx = px; xx < px + nx; xx++) { for (xx = px; xx < px + nx; xx++) {
gl = grid_get_line(gd, yy); gl = grid_get_line(gd, yy);
sgl = grid_get_line(s->grid, s->cy); sgl = grid_get_line(s->grid, s->cy);
@@ -660,7 +660,7 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
break; break;
grid_view_set_cell(s->grid, s->cx, s->cy, &gc); grid_view_set_cell(s->grid, s->cx, s->cy, &gc);
if (!screen_redraw_is_visible(r, xoff + s->cx)) if (!window_position_is_visible(r, xoff + s->cx))
break; break;
ttyctx.cell = &gc; ttyctx.cell = &gc;
ttyctx.flags &= (TTY_CTX_OVERLAY_SYNC|TTY_CTX_SYNC); ttyctx.flags &= (TTY_CTX_OVERLAY_SYNC|TTY_CTX_SYNC);
@@ -1165,7 +1165,7 @@ screen_write_redraw_line(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
if (s->mode & MODE_SYNC) if (s->mode & MODE_SYNC)
return; return;
r = screen_redraw_get_visible_ranges(wp, xoff, yoff + yy, sx, NULL); r = window_visible_ranges(wp, xoff, yoff + yy, sx, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
if (ri->nx == 0) if (ri->nx == 0)
@@ -1853,8 +1853,8 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
/* First line (containing the cursor). */ /* First line (containing the cursor). */
if (s->cx <= sx - 1) { if (s->cx <= sx - 1) {
r = screen_redraw_get_visible_ranges(ctx->wp, xoff + s->cx, r = window_visible_ranges(ctx->wp, xoff + s->cx, yoff + s->cy,
yoff + s->cy, sx - s->cx, NULL); sx - s->cx, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
if (ri->nx == 0) if (ri->nx == 0)
@@ -1867,8 +1867,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
/* Below cursor to bottom. */ /* Below cursor to bottom. */
for (y = s->cy + 1; y < sy; y++) { for (y = s->cy + 1; y < sy; y++) {
screen_write_set_cursor(ctx, 0, y); screen_write_set_cursor(ctx, 0, y);
r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + y, r = window_visible_ranges(ctx->wp, xoff, yoff + y, sx, NULL);
sx, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
if (ri->nx == 0) if (ri->nx == 0)
@@ -1930,8 +1929,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
/* Top to above the cursor. */ /* Top to above the cursor. */
for (y = 0; y < s->cy; y++) { for (y = 0; y < s->cy; y++) {
screen_write_set_cursor(ctx, 0, y); screen_write_set_cursor(ctx, 0, y);
r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + y, r = window_visible_ranges(ctx->wp, xoff, yoff + y, sx, NULL);
sx, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
if (ri->nx == 0) if (ri->nx == 0)
@@ -1943,8 +1941,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
/* Last line (containing the cursor). */ /* Last line (containing the cursor). */
screen_write_set_cursor(ctx, 0, s->cy); screen_write_set_cursor(ctx, 0, s->cy);
r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + ocy, r = window_visible_ranges(ctx->wp, xoff, yoff + ocy, s->cx + 1, NULL);
s->cx + 1, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
if (ri->nx == 0) if (ri->nx == 0)
@@ -2005,8 +2002,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
/* Clear every line. */ /* Clear every line. */
for (y = 0; y < sy; y++) { for (y = 0; y < sy; y++) {
screen_write_set_cursor(ctx, 0, y); screen_write_set_cursor(ctx, 0, y);
r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + y, r = window_visible_ranges(ctx->wp, xoff, yoff + y, sx, NULL);
sx, NULL);
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
if (ri->nx == 0) if (ri->nx == 0)
@@ -2230,7 +2226,7 @@ screen_write_collect_flush_line(struct screen_write_ctx *ctx, u_int y)
if (y + yoff >= wsy) if (y + yoff >= wsy)
return (0); return (0);
r = screen_redraw_get_visible_ranges(wp, 0, y + yoff, wsx, NULL); r = window_visible_ranges(wp, 0, y + yoff, wsx, NULL);
TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) {
log_debug("collect list: x=%u (last %u), y=%u, used=%u", ci->x, log_debug("collect list: x=%u (last %u), y=%u, used=%u", ci->x,
last, y, ci->used); last, y, ci->used);
@@ -2625,8 +2621,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
xoff = wp->xoff; xoff = wp->xoff;
yoff = wp->yoff; yoff = wp->yoff;
} }
r = screen_redraw_get_visible_ranges(wp, xoff + s->cx, s->cy + yoff, r = window_visible_ranges(wp, xoff + s->cx, s->cy + yoff, width, NULL);
width, NULL);
/* /*
* Move the cursor. If not wrapping, stick at the last character and * Move the cursor. If not wrapping, stick at the last character and
@@ -2798,7 +2793,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
*/ */
if (wp != NULL) if (wp != NULL)
yoff = wp->yoff; yoff = wp->yoff;
r = screen_redraw_get_visible_ranges(wp, cx - n, cy + yoff, n, NULL); r = window_visible_ranges(wp, cx - n, cy + yoff, n, NULL);
for (i = 0, vis = 0; i < r->used; i++) for (i = 0, vis = 0; i < r->used; i++)
vis += r->ranges[i].nx; vis += r->ranges[i].nx;
if (vis < n) { if (vis < n) {

View File

@@ -627,6 +627,9 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
pane_status_line = wp->yoff + wp->sy; pane_status_line = wp->yoff + wp->sy;
else else
pane_status_line = -1; /* not used */ pane_status_line = -1; /* not used */
bdr_left = wp->xoff - 1;
if (sb_pos == PANE_SCROLLBARS_LEFT)
bdr_left -= sb_pad + sb_w;
/* Check if point is within the pane or scrollbar. */ /* Check if point is within the pane or scrollbar. */
if (((pane_status != PANE_STATUS_OFF && if (((pane_status != PANE_STATUS_OFF &&
@@ -657,7 +660,7 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
return (KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN); return (KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN);
} else if (window_pane_is_floating(wp) && } else if (window_pane_is_floating(wp) &&
window_pane_get_pane_lines(wp) != PANE_LINES_NONE && window_pane_get_pane_lines(wp) != PANE_LINES_NONE &&
(px == wp->xoff - 1 || (px == bdr_left ||
py == wp->yoff - 1 || py == wp->yoff - 1 ||
py == wp->yoff + (int)wp->sy)) { py == wp->yoff + (int)wp->sy)) {
/* Floating pane left, bottom or top border. */ /* Floating pane left, bottom or top border. */
@@ -675,11 +678,20 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
if (window_pane_is_floating(fwp) && if (window_pane_is_floating(fwp) &&
window_pane_get_pane_lines(fwp) == PANE_LINES_NONE) window_pane_get_pane_lines(fwp) == PANE_LINES_NONE)
continue; continue;
if (window_pane_show_scrollbar(fwp, sb)) {
sb_w = fwp->scrollbar_style.width;
sb_pad = fwp->scrollbar_style.pad;
} else {
sb_w = 0;
sb_pad = 0;
}
bdr_top = fwp->yoff - 1; bdr_top = fwp->yoff - 1;
bdr_bottom = fwp->yoff + fwp->sy; bdr_bottom = fwp->yoff + fwp->sy;
if (sb_pos == PANE_SCROLLBARS_LEFT) bdr_left = fwp->xoff - 1;
if (sb_pos == PANE_SCROLLBARS_LEFT) {
bdr_left -= sb_pad + sb_w;
bdr_right = fwp->xoff + fwp->sx; bdr_right = fwp->xoff + fwp->sx;
else { } else {
/* PANE_SCROLLBARS_RIGHT or none. */ /* PANE_SCROLLBARS_RIGHT or none. */
bdr_right = fwp->xoff + fwp->sx + sb_pad + sb_w; bdr_right = fwp->xoff + fwp->sx + sb_pad + sb_w;
} }
@@ -689,13 +701,11 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
break; break;
if (window_pane_is_floating(wp)) { if (window_pane_is_floating(wp)) {
/* Floating pane, check left border. */ /* Floating pane, check left border. */
bdr_left = fwp->xoff - 1;
if (px == bdr_left) if (px == bdr_left)
break; break;
} }
} }
if (px >= fwp->xoff - 1 && if (px >= bdr_left && px <= fwp->xoff + (int)fwp->sx) {
px <= fwp->xoff + (int)fwp->sx) {
bdr_bottom = fwp->yoff + fwp->sy; bdr_bottom = fwp->yoff + fwp->sy;
if (py == bdr_bottom) if (py == bdr_bottom)
break; break;
@@ -1837,8 +1847,8 @@ server_client_reset_state(struct client *c)
cx = wp->xoff + (int)s->cx - (int)ox; cx = wp->xoff + (int)s->cx - (int)ox;
cy = wp->yoff + (int)s->cy - (int)oy; cy = wp->yoff + (int)s->cy - (int)oy;
r = screen_redraw_get_visible_ranges(wp, cx, cy, 1, NULL); r = window_visible_ranges(wp, cx, cy, 1, NULL);
if (!screen_redraw_is_visible(r, cx)) if (!window_position_is_visible(r, cx))
cursor = 0; cursor = 0;
if (status_at_line(c) == 0) if (status_at_line(c) == 0)

2
tmux.1
View File

@@ -3430,7 +3430,7 @@ which may be one of:
.It Li "top-left-centre" Ta "Centre of top-left quadrant" .It Li "top-left-centre" Ta "Centre of top-left quadrant"
.It Li "top-right-centre" Ta "Centre of top-right quadrant" .It Li "top-right-centre" Ta "Centre of top-right quadrant"
.It Li "bottom-left-centre" Ta "Centre of bottom-left quadrant" .It Li "bottom-left-centre" Ta "Centre of bottom-left quadrant"
.It Li "bottom-right-centre" Ta "Centre of botton-right quadrant" .It Li "bottom-right-centre" Ta "Centre of bottom-right quadrant"
.It Li "front" Ta "Front of floating panes" .It Li "front" Ta "Front of floating panes"
.It Li "back" Ta "Back of floating panes" .It Li "back" Ta "Back of floating panes"
.It Li "forward" Ta "Forward one floating pane" .It Li "forward" Ta "Forward one floating pane"

8
tmux.h
View File

@@ -3396,9 +3396,6 @@ void screen_write_alternateoff(struct screen_write_ctx *,
/* screen-redraw.c */ /* screen-redraw.c */
void screen_redraw_screen(struct client *); void screen_redraw_screen(struct client *);
void screen_redraw_pane(struct client *, struct window_pane *, int); void screen_redraw_pane(struct client *, struct window_pane *, int);
int screen_redraw_is_visible(struct visible_ranges *, u_int);
struct visible_ranges *screen_redraw_get_visible_ranges(struct window_pane *,
int, int, u_int, struct visible_ranges *);
/* screen.c */ /* screen.c */
void screen_init(struct screen *, u_int, u_int, u_int); void screen_init(struct screen *, u_int, u_int, u_int);
@@ -3547,6 +3544,11 @@ struct style_range *window_pane_status_get_range(struct window_pane *, u_int,
int window_pane_is_floating(struct window_pane *); int window_pane_is_floating(struct window_pane *);
int window_pane_is_hidden(struct window_pane *); int window_pane_is_hidden(struct window_pane *);
/* window-visible.c */
int window_position_is_visible(struct visible_ranges *, u_int);
struct visible_ranges *window_visible_ranges(struct window_pane *, int, int,
u_int, struct visible_ranges *);
/* layout.c */ /* layout.c */
u_int layout_count_cells(struct layout_cell *); u_int layout_count_cells(struct layout_cell *);
struct layout_cell *layout_create_cell(struct layout_cell *); struct layout_cell *layout_create_cell(struct layout_cell *);

View File

@@ -5403,8 +5403,12 @@ window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
u_int maxx; u_int maxx;
int allow_onemore; int allow_onemore;
allow_onemore = (data->screen.sel != NULL && data->rectflag); /*
if (cy < screen_size_y(s)) { * Allow rectangle selection to extend past end of current line to
* behave the same as vi with virtualedit=block set.
*/
if (!data->rectflag && cy < screen_size_y(s)) {
allow_onemore = (data->screen.sel != NULL && data->rectflag);
py = screen_hsize(data->backing) + cy - data->oy; py = screen_hsize(data->backing) + cy - data->oy;
maxx = window_copy_cursor_limit(wme, py, allow_onemore); maxx = window_copy_cursor_limit(wme, py, allow_onemore);
if (cx > maxx) if (cx > maxx)

224
window-visible.c Normal file
View File

@@ -0,0 +1,224 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Check if a single character is within a visible range (not obscured by a
* floating pane).
*/
int
window_position_is_visible(struct visible_ranges *r, u_int px)
{
u_int i;
struct visible_range *ri;
if (r == NULL)
return (1);
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
if (ri->nx != 0 && px >= ri->px && px < ri->px + ri->nx)
return (1);
}
return (0);
}
/*
* Construct ranges array for the line at starting at px,py of width cells of
* base_wp that are unobsructed. All ranges are in window coordinates.
*/
struct visible_ranges *
window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
struct visible_ranges *r)
{
struct window_pane *wp;
struct window *w;
struct visible_range *ri;
static struct visible_ranges sr = { NULL, 0, 0 };
int found_self, sb, sb_w, sb_pos;
int lb, rb, tb, bb, sx, ex, no_border;
u_int i, s;
if (py < 0 || width == 0)
goto empty;
if (px < 0) {
if ((u_int)-px >= width)
goto empty;
width -= (u_int)-px;
px = 0;
}
if (base_wp == NULL) {
if (r != NULL)
return (r);
if (sr.ranges == NULL)
sr.ranges = xcalloc(1, sizeof *sr.ranges);
sr.ranges[0].px = px;
sr.ranges[0].nx = width;
sr.size = 1;
sr.used = 1;
return (&sr);
}
w = base_wp->window;
if ((u_int)py >= w->sy)
goto empty;
if (px + width > w->sx)
width = w->sx - px;
if (r == NULL) {
/* Start with the entire width of the range. */
server_client_ensure_ranges(&base_wp->r, 1);
r = &base_wp->r;
r->ranges[0].px = px;
r->ranges[0].nx = width;
r->used = 1;
}
sb = options_get_number(w->options, "pane-scrollbars");
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
found_self = 0;
TAILQ_FOREACH_REVERSE(wp, &w->z_index, window_panes_zindex, zentry) {
if (wp == base_wp) {
found_self = 1;
continue;
}
if (window_pane_is_floating(wp) &&
window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
no_border = 1;
else
no_border = 0;
if (no_border) {
tb = wp->yoff;
bb = wp->yoff + (int)wp->sy - 1;
} else {
tb = wp->yoff > 0 ? wp->yoff - 1 : 0;
bb = wp->yoff + (int)wp->sy;
}
if (!found_self ||
!window_pane_is_visible(wp) ||
py < tb ||
py > bb)
continue;
if (!window_pane_is_floating(wp) && (py == tb || py == bb))
continue;
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
if (!window_pane_show_scrollbar(wp, sb))
sb_w = sb_pos = 0;
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
if (no_border) {
lb = wp->xoff;
rb = wp->xoff + (int)wp->sx - 1;
} else if (sb_pos == PANE_SCROLLBARS_LEFT) {
if (wp->xoff > sb_w)
lb = wp->xoff - 1 - sb_w;
else
lb = 0;
} else { /* PANE_SCROLLBARS_RIGHT or none. */
if (wp->xoff > 0)
lb = wp->xoff - 1;
else
lb = 0;
}
if (!no_border) {
if (sb_pos == PANE_SCROLLBARS_LEFT)
rb = wp->xoff + (int)wp->sx;
else /* PANE_SCROLLBARS_RIGHT or none. */
rb = wp->xoff + (int)wp->sx + sb_w;
}
if (lb < 0)
lb = 0;
if (rb < 0)
continue;
if (no_border && rb >= (int)w->sx)
rb = w->sx - 1;
else if (!no_border && rb > (int)w->sx)
rb = w->sx - 1;
sx = ri->px;
ex = sx + ri->nx - 1;
if (lb > sx && lb <= ex && rb > ex) {
/*
* If the left edge of floating pane falls
* inside this range and right edge covers up
* to right of range, then shrink left edge of
* range.
*/
ri->nx = lb - sx;
} else if (rb >= sx && rb <= ex && lb <= sx) {
/*
* Else if the right edge of floating pane falls
* inside of this range and left edge covers
* the left of range, then move px forward to
* right edge of pane.
*/
ri->nx = ex - rb;
ri->px = rb + 1;
} else if (lb > sx && rb <= ex) {
/*
* Else if pane fully inside range then split
* into 2 ranges.
*/
server_client_ensure_ranges(r, r->used + 1);
for (s = r->used; s > i; s--) {
memcpy(&r->ranges[s], &r->ranges[s - 1],
sizeof *r->ranges);
}
ri = &r->ranges[i];
r->ranges[i + 1].px = rb + 1;
r->ranges[i + 1].nx = ex - rb;
/* ri->px was copied, unchanged. */
ri->nx = lb - sx;
r->used++;
} else if (lb <= sx && rb > ex) {
/*
* If floating pane completely covers this range
* then delete it (make it 0 length).
*/
ri->nx = 0;
} else {
/*
* The range is already obscured, do
* nothing.
*/
}
}
}
return (r);
empty:
if (r == NULL) {
if (sr.ranges == NULL)
sr.ranges = xcalloc(1, sizeof *sr.ranges);
sr.size = 1;
sr.used = 0;
return (&sr);
}
r->used = 0;
return (r);
}