diff --git a/Makefile.am b/Makefile.am index b0244f0f..8fcbdd0c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -217,6 +217,7 @@ dist_tmux_SOURCES = \ window-copy.c \ window-customize.c \ window-tree.c \ + window-visible.c \ window.c \ xmalloc.c \ xmalloc.h diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 0d8d83fd..da15e8b5 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -114,7 +114,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) w->active = wp; w->latest = tc; - if (name != NULL) { + if (name == NULL) { newname = default_window_name(w); window_set_name(w, newname, WINDOW_NAME_FORBID); free(newname); diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 53e7989b..56e13333 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -65,8 +65,7 @@ cmd_display_panes_put(struct screen_redraw_ctx *ctx, struct visible_range *ri; u_int i, j; - r = screen_redraw_get_visible_ranges(wp, ctx->ox + cx, ctx->oy + cy, - len, NULL); + r = window_visible_ranges(wp, ctx->ox + cx, ctx->oy + cy, len, NULL); for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; 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); 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++) { ri = &r->ranges[i]; tty_draw_line(tty, &screen, ri->px - px, 0, ri->nx, diff --git a/cmd-new-window.c b/cmd-new-window.c index c7a203e2..c65745a2 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -61,7 +61,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) struct session *s = target->s; struct winlink *wl = target->wl, *new_wl = NULL; int idx = target->idx, before; - char *cause = NULL, *cp, *expanded, *wname; + char *cause = NULL, *cp, *expanded, *wname = NULL; const char *template, *name; struct cmd_find_state fs; struct args_value *av; diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 72f871d7..5ea3b03b 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -226,6 +226,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m) struct window_pane *wp; struct layout_cell *lc; int y, ly, x, lx, sx, sy, new_sx, new_sy; + int scrollbars, sb_pos, left, right; int new_xoff, new_yoff, resizes = 0; 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; sx = wp->sx; 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; 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) 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. */ new_sx = lc->sx + (lx - x); 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; layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff); resizes++; - } else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) && + } else if ((lx == right + 1 || lx == right) && ly == wp->yoff - 1) { /* Top right corner. */ 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; layout_set_size(lc, new_sx, new_sy, lc->xoff, new_yoff); resizes++; - } else if ((lx == wp->xoff - 1 || lx == wp->xoff) && + } else if ((lx == left || lx == left + 1) && ly == wp->yoff + sy) { /* Bottom left corner. */ 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; layout_set_size(lc, new_sx, new_sy, new_xoff, lc->yoff); resizes++; - } else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) && + } else if ((lx == right + 1 || lx == right) && ly == wp->yoff + sy) { /* Bottom right corner. */ 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; layout_set_size(lc, new_sx, new_sy, lc->xoff, lc->yoff); resizes++; - } else if (lx == wp->xoff + sx + 1) { + } else if (lx == right) { /* Right border. */ new_sx = x - lc->xoff; if (new_sx < PANE_MINIMUM) return; layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff); resizes++; - } else if (lx == wp->xoff - 1) { + } else if (lx == left) { /* Left border. */ new_sx = lc->sx + (lx - x); if (new_sx < PANE_MINIMUM) diff --git a/configure.ac b/configure.ac index 093d855b..e2a5f169 100644 --- a/configure.ac +++ b/configure.ac @@ -297,24 +297,24 @@ fi # Look for ncurses or curses. Try pkg-config first then directly for the # library. PKG_CHECK_MODULES( - LIBTINFO, - tinfo, + LIBTINFOW, + tinfow, [ - AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS" - CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS" - LIBS="$LIBTINFO_LIBS $LIBS" + AM_CPPFLAGS="$LIBTINFOW_CFLAGS $AM_CPPFLAGS" + CPPFLAGS="$LIBTINFOW_CFLAGS $SAVED_CPPFLAGS" + LIBS="$LIBTINFOW_LIBS $LIBS" found_ncurses=yes ], found_ncurses=no ) if test "x$found_ncurses" = xno; then PKG_CHECK_MODULES( - LIBNCURSES, - ncurses, + LIBTINFO, + tinfo, [ - AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS" - CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS" - LIBS="$LIBNCURSES_LIBS $LIBS" + AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS" + CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS" + LIBS="$LIBTINFO_LIBS $LIBS" found_ncurses=yes ], found_ncurses=no @@ -333,10 +333,23 @@ if test "x$found_ncurses" = xno; then found_ncurses=no ) 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 AC_SEARCH_LIBS( setupterm, - [tinfo terminfo ncurses ncursesw], + [tinfow tinfo terminfo ncursesw ncurses], found_ncurses=yes, found_ncurses=no ) diff --git a/layout.c b/layout.c index 08501b43..0af2199b 100644 --- a/layout.c +++ b/layout.c @@ -28,10 +28,10 @@ * 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 * 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 - * as a part of the tiled layout. A 'neighbour' is a sibling that is also tiled. - * A cell's 'split' size refers to the side that is shortened when splitting it, - * determined by the parent's type. + * contains a window pane. A leaf is considered to be 'tiled' if it is to be + * drawn as a part of the tiled layout. A 'neighbour' is a sibling that is also + * tiled. A cell's 'split' size refers to the side that is shortened when + * splitting it, determined by the parent's type. * * 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 @@ -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. */ static void layout_fix_offsets1(struct layout_cell *lc) @@ -725,8 +768,10 @@ out: lc->parent = lcparent->parent; if (lc->parent == NULL) { - if (layout_cell_is_tiled(lc)) - layout_set_size(lc, w->sx, w->sy, 0, 0); + if (layout_cell_is_tiled(lc)) { + lc->xoff = 0; + lc->yoff = 0; + } *lcroot = lc; } else TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); diff --git a/screen-redraw.c b/screen-redraw.c index 8aa175c1..e1a5655b 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -129,7 +129,7 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, int hsplit = 0, vsplit = 0; int pane_status = window_pane_get_pane_status(wp); 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; if (pane_scrollbars != 0) @@ -151,20 +151,19 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, /* Floating pane borders. */ 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 (sb_pos == PANE_SCROLLBARS_LEFT) { - if (px == wp->xoff - 1 - sb_w) - return (SCREEN_REDRAW_BORDER_LEFT); - if (px == wp->xoff + sx) - 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 == left) + return (SCREEN_REDRAW_BORDER_LEFT); + if (px == right) + return (SCREEN_REDRAW_BORDER_RIGHT); } - if (px >= wp->xoff && px <= wp->xoff + sx) { + if (px > left && px <= right) { if (py == wp->yoff - 1) return (SCREEN_REDRAW_BORDER_TOP); 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 = screen_redraw_get_visible_ranges(wp, x, yoff, width, r); + r = window_visible_ranges(wp, x, yoff, width, r); if (ctx->statustop) yoff += ctx->statuslines; 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); } -/* - * 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. */ 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. */ 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++) { ri = &r->ranges[k]; if (ri->nx == 0) @@ -1595,7 +1395,7 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx, wy = sb_wy + j; /* window y coordinate */ py = sb_tty_y + j; /* tty y coordinate */ 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++) { px = sb_x + ox + i; /* tty 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 || wy < yoff - 1 || py >= sy || py < 0 || - !screen_redraw_is_visible(r, wx)) + !window_position_is_visible(r, wx)) continue; tty_cursor(tty, px, py); if ((sb_pos == PANE_SCROLLBARS_LEFT && diff --git a/screen-write.c b/screen-write.c index ba1dea86..f8219fdb 100644 --- a/screen-write.c +++ b/screen-write.c @@ -647,8 +647,8 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, break; s->cx = cx; screen_write_initctx(ctx, &ttyctx, 0, 0); - r = screen_redraw_get_visible_ranges(wp, xoff + s->cx, - s->cy + yoff, nx, NULL); + r = window_visible_ranges(wp, xoff + s->cx, s->cy + yoff, nx, + NULL); for (xx = px; xx < px + nx; xx++) { gl = grid_get_line(gd, yy); 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; 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; ttyctx.cell = &gc; 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) 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++) { ri = &r->ranges[i]; if (ri->nx == 0) @@ -1853,8 +1853,8 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) /* First line (containing the cursor). */ if (s->cx <= sx - 1) { - r = screen_redraw_get_visible_ranges(ctx->wp, xoff + s->cx, - yoff + s->cy, sx - s->cx, NULL); + r = window_visible_ranges(ctx->wp, xoff + s->cx, yoff + s->cy, + sx - s->cx, NULL); for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; if (ri->nx == 0) @@ -1867,8 +1867,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) /* Below cursor to bottom. */ for (y = s->cy + 1; y < sy; y++) { screen_write_set_cursor(ctx, 0, y); - r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + y, - sx, NULL); + r = window_visible_ranges(ctx->wp, xoff, yoff + y, sx, NULL); for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; if (ri->nx == 0) @@ -1930,8 +1929,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg) /* Top to above the cursor. */ for (y = 0; y < s->cy; y++) { screen_write_set_cursor(ctx, 0, y); - r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + y, - sx, NULL); + r = window_visible_ranges(ctx->wp, xoff, yoff + y, sx, NULL); for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; if (ri->nx == 0) @@ -1943,8 +1941,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg) /* Last line (containing the cursor). */ screen_write_set_cursor(ctx, 0, s->cy); - r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + ocy, - s->cx + 1, NULL); + r = window_visible_ranges(ctx->wp, xoff, yoff + ocy, s->cx + 1, NULL); for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; if (ri->nx == 0) @@ -2005,8 +2002,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) /* Clear every line. */ for (y = 0; y < sy; y++) { screen_write_set_cursor(ctx, 0, y); - r = screen_redraw_get_visible_ranges(ctx->wp, xoff, yoff + y, - sx, NULL); + r = window_visible_ranges(ctx->wp, xoff, yoff + y, sx, NULL); for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; 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) 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) { log_debug("collect list: x=%u (last %u), y=%u, used=%u", ci->x, last, y, ci->used); @@ -2625,8 +2621,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) xoff = wp->xoff; yoff = wp->yoff; } - r = screen_redraw_get_visible_ranges(wp, xoff + s->cx, s->cy + yoff, - width, NULL); + r = window_visible_ranges(wp, xoff + s->cx, s->cy + yoff, width, NULL); /* * 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) 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++) vis += r->ranges[i].nx; if (vis < n) { diff --git a/server-client.c b/server-client.c index 2e7194b5..26e9c526 100644 --- a/server-client.c +++ b/server-client.c @@ -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; else 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. */ 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); } else if (window_pane_is_floating(wp) && window_pane_get_pane_lines(wp) != PANE_LINES_NONE && - (px == wp->xoff - 1 || + (px == bdr_left || py == wp->yoff - 1 || py == wp->yoff + (int)wp->sy)) { /* 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) && window_pane_get_pane_lines(fwp) == PANE_LINES_NONE) 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_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; - else { + } else { /* PANE_SCROLLBARS_RIGHT or none. */ 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; if (window_pane_is_floating(wp)) { /* Floating pane, check left border. */ - bdr_left = fwp->xoff - 1; if (px == bdr_left) break; } } - if (px >= fwp->xoff - 1 && - px <= fwp->xoff + (int)fwp->sx) { + if (px >= bdr_left && px <= fwp->xoff + (int)fwp->sx) { bdr_bottom = fwp->yoff + fwp->sy; if (py == bdr_bottom) break; @@ -1837,8 +1847,8 @@ server_client_reset_state(struct client *c) cx = wp->xoff + (int)s->cx - (int)ox; cy = wp->yoff + (int)s->cy - (int)oy; - r = screen_redraw_get_visible_ranges(wp, cx, cy, 1, NULL); - if (!screen_redraw_is_visible(r, cx)) + r = window_visible_ranges(wp, cx, cy, 1, NULL); + if (!window_position_is_visible(r, cx)) cursor = 0; if (status_at_line(c) == 0) diff --git a/tmux.1 b/tmux.1 index 5f9b71fd..cb0813a6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3430,7 +3430,7 @@ which may be one of: .It Li "top-left-centre" Ta "Centre of top-left 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-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 "back" Ta "Back of floating panes" .It Li "forward" Ta "Forward one floating pane" diff --git a/tmux.h b/tmux.h index f42c433a..dedd36f1 100644 --- a/tmux.h +++ b/tmux.h @@ -3396,9 +3396,6 @@ void screen_write_alternateoff(struct screen_write_ctx *, /* screen-redraw.c */ void screen_redraw_screen(struct client *); 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 */ 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_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 */ u_int layout_count_cells(struct layout_cell *); struct layout_cell *layout_create_cell(struct layout_cell *); diff --git a/window-copy.c b/window-copy.c index f06b179b..272e2e9e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -5403,8 +5403,12 @@ window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy) u_int maxx; 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; maxx = window_copy_cursor_limit(wme, py, allow_onemore); if (cx > maxx) diff --git a/window-visible.c b/window-visible.c new file mode 100644 index 00000000..7feb496d --- /dev/null +++ b/window-visible.c @@ -0,0 +1,224 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * + * 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 + +#include +#include + +#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); +}